2016-03-07 21 views
9

Io uso lo StrUtils per dividere una stringa in TStringDynArray, ma l'output non era come previsto. Cercherò di spiegare il problema:StrUtils.SplitString non funziona come previsto

ho una stringa di str: 'a'; 'b'; 'c'
Ora ho chiamato StrUtils.SplitString(str, '; '); di dividere la corda e mi aspettavo un array con tre elementi: 'a', 'b', 'c'

ma quello che ho got è un array con cinque elementi: 'a', '', 'b', '', 'c'.
Quando divido con solo ';' anziché '; ' ottengo tre elementi con uno spazio vuoto iniziale.

Quindi perché ottengo stringhe vuote nella mia prima soluzione?

+3

Leggi i documenti. Forse non come previsto, ma funziona come documentato. –

+0

Questa domanda ha alcuni suggerimenti sulla divisione di una stringa, basata su una stringa multi-carattere (cosa che si aspettava che stesse facendo), ma la maggior parte di essi funziona con liste di stringhe, non con array: http://stackoverflow.com/questions/15424293/how-to-split-string-by-a-multi-character-delimiter – quasoft

risposta

15

Questa funzione è progettata per non unire separatori consecutivi. Per esempio, pensare di dividere la seguente stringa su virgole:

foo,,bar 

Che cosa vi aspettate SplitString('foo,,bar', ',') di tornare? Vorresti cercare ('foo', 'bar') o la risposta sarebbe ('foo', '', 'bar')? Non è chiaro a priori che sia giusto, e casi d'uso diversi potrebbero volere output diversi.

Se il tuo caso, hai specificato due delimitatori, ';' e ' '. Ciò significa che

'a'; 'b' 

divide in ';' e di nuovo a ' '. Tra questi due delimitatori non c'è nulla e quindi viene restituita una stringa vuota tra 'a' e 'b'.

Il metodo Split dal string helper introdotto in XE3 ha un parametro TStringSplitOptions. Se si passa ExcludeEmpty per quel parametro, i separatori consecutivi vengono considerati come un singolo separatore. Questo programma:

{$APPTYPE CONSOLE} 

uses 
    System.SysUtils; 

var 
    S: string; 

begin 
    for S in '''a''; ''b''; ''c'''.Split([';', ' '], ExcludeEmpty) do begin 
    Writeln(S); 
    end; 
end. 

uscite:

 
'a' 
'b' 
'c' 

Ma voi non avete questo a vostra disposizione in XE2 quindi penso che si sta andando ad avere per rotolare il proprio funzione split. Quale potrebbe essere il seguente:

function IsSeparator(const C: Char; const Separators: string): Boolean; 
var 
    sep: Char; 
begin 
    for sep in Separators do begin 
    if sep=C then begin 
     Result := True; 
     exit; 
    end; 
    end; 
    Result := False; 
end; 

function Split(const Str, Separators: string): TArray<string>; 
var 
    CharIndex, ItemIndex: Integer; 
    len: Integer; 
    SeparatorCount: Integer; 
    Start: Integer; 
begin 
    len := Length(Str); 
    if len=0 then begin 
    Result := nil; 
    exit; 
    end; 

    SeparatorCount := 0; 
    for CharIndex := 1 to len do begin 
    if IsSeparator(Str[CharIndex], Separators) then begin 
     inc(SeparatorCount); 
    end; 
    end; 

    SetLength(Result, SeparatorCount+1); // potentially an over-allocation 
    ItemIndex := 0; 
    Start := 1; 
    CharIndex := 1; 
    for CharIndex := 1 to len do begin 
    if IsSeparator(Str[CharIndex], Separators) then begin 
     if CharIndex>Start then begin 
     Result[ItemIndex] := Copy(Str, Start, CharIndex-Start); 
     inc(ItemIndex); 
     end; 
     Start := CharIndex+1; 
    end; 
    end; 

    if len>Start then begin 
    Result[ItemIndex] := Copy(Str, Start, len-Start+1); 
    inc(ItemIndex); 
    end; 

    SetLength(Result, ItemIndex); 
end; 

Naturalmente, tutto ciò presuppone che si desideri che uno spazio operi come separatore. L'hai chiesto nel codice, ma forse in realtà vuoi solo che ; funga da separatore. In tal caso, probabilmente si desidera passare ';' come separatore e tagliare le stringhe restituite.

+0

grazie per questa spiegazione dettagliata! –

14

SplitString è definito come

function SplitString(const S, Delimiters: string): TStringDynArray; 

Uno avrebbe pensato che Delimiters denotano stringa delimitatore singolo usata per stringa scissione, ma in realtà denota insieme di singoli caratteri utilizzati per stringa divisa. Ogni carattere nella stringa Delimiters verrà utilizzato come uno dei possibili delimitatori.

SplitString

divide una stringa in diverse parti delimitate dai specificati delimitatore caratteri. SplitString divide una stringa in parti diverse delimitate dal delimitatore specificato caratteri. S è la stringa da dividere . Delimitatori è una stringa contenente i caratteri definiti come delimitatori .

+1

Suppongo che l'avrebbero chiamato 'Delimitatore' (singolare) quindi, non' Delimitatori'. FWIW, Nelle versioni successive, 'TStringHelper' ha una versione di' Split' che accetta anche la stringa come delimitatore, non solo i caratteri, ma sfortunatamente non in XE2. –

+0

@RudyVelthuis Concordato. Ma la linea sottile tra il Delimitatore e il Delimitatore può essere persa se non sei un madrelingua inglese. Oltre a ciò, le operazioni di divisione in altre lingue di solito prendono il delimitatore esatto completo, quindi l'implementazione di Delphi è piuttosto confusa anche da questo aspetto. –

+0

@RudyVelthuis, ma Split ha anche una sua serie di stranezze: http://stackoverflow.com/questions/28410901/string-split-works-strange-when-last-value-is-empty –

5

È perché il secondo parametro di SplitString è un elenco di delimitatori di carattere singolo, quindi '; 'significa dividere in un'; ' O dividere in un ''. Quindi la stringa è divisa in ogni ';' e in ogni spazio, e tra il ';' e il "non c'è nulla, quindi le corde vuote.

Problemi correlati