Próbuję znaleźć funkcję Delphi, która podzieli ciąg wejściowy na tablicę ciągów na podstawie ogranicznika. Znalazłem wiele w Google, ale wydaje się, że wszystkie mają swoje własne problemy i nie byłem w stanie zmusić żadnego z nich do działania.
Muszę tylko podzielić ciąg, taki jak
"word:doc,txt,docx"
:, na tablicę opartą na ':'. Wynik byłby
['word', 'doc,txt,docx']
.
Czy ktoś ma funkcję, o której wiedzą, że działa?
Dziękuję Ci
Nie ma potrzeby tworzenia
Split
funkcji. To już istnieje, zobClasses.ExtractStrings
.Używaj go w następujący sposób:
program Project1; {$APPTYPE CONSOLE} uses Classes; var List: TStrings; begin List := TStringList.Create; try ExtractStrings([':'], [], PChar('word:doc,txt,docx'), List); WriteLn(List.Text); ReadLn; finally List.Free; end; end.
I w pełni odpowiedzieć na to pytanie;
List
reprezentuje żądaną tablicę z elementami:List[0] = 'word' List[1] = 'doc,txt,docx'
źródło
split
funkcji, ale potrzebaTStrings
obiektu. A ze względu na brak elastyczności (@awmross) wspomina, wolałbym rozwiązanie FrankaMożesz użyć
StrUtils.SplitString
.function SplitString(const S, Delimiters: string): TStringDynArray;
Jego opis z dokumentacji :
źródło
Korzystanie z funkcji SysUtils.TStringHelper.Split , wprowadzonej w Delphi XE3:
var MyString: String; Splitted: TArray<String>; begin MyString := 'word:doc,txt,docx'; Splitted := MyString.Split([':']); end.
Spowoduje to podzielenie ciągu z podanym separatorem na tablicę ciągów.
źródło
Zawsze używam czegoś podobnego do tego:
Uses StrUtils, Classes; Var Str, Delimiter : String; begin // Str is the input string, Delimiter is the delimiter With TStringList.Create Do try Text := ReplaceText(S,Delim,#13#10); // From here on and until "finally", your desired result strings are // in strings[0].. strings[Count-1) finally Free; //Clean everything up, and liberate your memory ;-) end; end;
źródło
Strutils::AnsiReplaceText
list.Text := AnsiReplaceStr(source, delimiter, #13#10);
.Podobna do funkcji Explode () oferowanej przez Mef, ale z kilkoma różnicami (z których jedną uważam za poprawkę błędu):
type TArrayOfString = array of String; function SplitString(const aSeparator, aString: String; aMax: Integer = 0): TArrayOfString; var i, strt, cnt: Integer; sepLen: Integer; procedure AddString(aEnd: Integer = -1); var endPos: Integer; begin if (aEnd = -1) then endPos := i else endPos := aEnd + 1; if (strt < endPos) then result[cnt] := Copy(aString, strt, endPos - strt) else result[cnt] := ''; Inc(cnt); end; begin if (aString = '') or (aMax < 0) then begin SetLength(result, 0); EXIT; end; if (aSeparator = '') then begin SetLength(result, 1); result[0] := aString; EXIT; end; sepLen := Length(aSeparator); SetLength(result, (Length(aString) div sepLen) + 1); i := 1; strt := i; cnt := 0; while (i <= (Length(aString)- sepLen + 1)) do begin if (aString[i] = aSeparator[1]) then if (Copy(aString, i, sepLen) = aSeparator) then begin AddString; if (cnt = aMax) then begin SetLength(result, cnt); EXIT; end; Inc(i, sepLen - 1); strt := i + 1; end; Inc(i); end; AddString(Length(aString)); SetLength(result, cnt); end;
Różnice:
Przykłady:
SplitString(':', 'abc') returns : result[0] = abc SplitString(':', 'a:b:c:') returns : result[0] = a result[1] = b result[2] = c result[3] = <empty string> SplitString(':', 'a:b:c:', 2) returns: result[0] = a result[1] = b
Jest to separator końcowy i hipotetyczny „pusty element końcowy”, który uważam za poprawkę błędu.
Dodałem również zasugerowaną przeze mnie zmianę alokacji pamięci, z doprecyzowaniem (błędnie zasugerowałem, że ciąg wejściowy może zawierać co najwyżej 50% separatorów, ale może oczywiście składać się ze 100% ciągów separatorów, dając tablicę pustych elementów!)
źródło
Explode to bardzo szybka funkcja, alhoritm źródła pochodzi z komponentu TStrings. Do eksplodowania używam kolejnego testu: Explode 134217733 bajtów danych, otrzymuję 19173962 elementy, czas pracy: 2984 ms.
Implode to funkcja o bardzo niskiej prędkości, ale piszę to łatwo.
{ ****************************************************************************** } { Explode/Implode (String <> String array) } { ****************************************************************************** } function Explode(S: String; Delimiter: Char): Strings; overload; var I, C: Integer; P, P1: PChar; begin SetLength(Result, 0); if Length(S) = 0 then Exit; P:=PChar(S+Delimiter); C:=0; while P^ <> #0 do begin P1:=P; while (P^ <> Delimiter) do P:=CharNext(P); Inc(C); while P^ in [#1..' '] do P:=CharNext(P); if P^ = Delimiter then begin repeat P:=CharNext(P); until not (P^ in [#1..' ']); end; end; SetLength(Result, C); P:=PChar(S+Delimiter); I:=-1; while P^ <> #0 do begin P1:=P; while (P^ <> Delimiter) do P:=CharNext(P); Inc(I); SetString(Result[I], P1, P-P1); while P^ in [#1..' '] do P:=CharNext(P); if P^ = Delimiter then begin repeat P:=CharNext(P); until not (P^ in [#1..' ']); end; end; end; function Explode(S: String; Delimiter: Char; Index: Integer): String; overload; var I: Integer; P, P1: PChar; begin if Length(S) = 0 then Exit; P:=PChar(S+Delimiter); I:=1; while P^ <> #0 do begin P1:=P; while (P^ <> Delimiter) do P:=CharNext(P); SetString(Result, P1, P-P1); if (I <> Index) then Inc(I) else begin SetString(Result, P1, P-P1); Exit; end; while P^ in [#1..' '] do P:=CharNext(P); if P^ = Delimiter then begin repeat P:=CharNext(P); until not (P^ in [#1..' ']); end; end; end; function Implode(S: Strings; Delimiter: Char): String; var iCount: Integer; begin Result:=''; if (Length(S) = 0) then Exit; for iCount:=0 to Length(S)-1 do Result:=Result+S[iCount]+Delimiter; System.Delete(Result, Length(Result), 1); end;
źródło
Strings
nie jest typem.var su : string; // What we want split si : TStringList; // Result of splitting Delimiter : string; ... Delimiter := ';'; si.Text := ReplaceStr(su, Delimiter, #13#10);
Linie na liście si będą zawierały podzielone ciągi.
źródło
Możesz stworzyć własną funkcję, która zwraca TArray ciągu:
function mySplit(input: string): TArray<string>; var delimiterSet: array [0 .. 0] of char; // split works with char array, not a single char begin delimiterSet[0] := '&'; // some character result := input.Split(delimiterSet); end;
źródło
Oto implementacja funkcji eksploduj, która jest dostępna w wielu innych językach programowania jako funkcja standardowa:
type TStringDynArray = array of String; function Explode(const Separator, S: string; Limit: Integer = 0): TStringDynArray; var SepLen: Integer; F, P: PChar; ALen, Index: Integer; begin SetLength(Result, 0); if (S = '') or (Limit < 0) then Exit; if Separator = '' then begin SetLength(Result, 1); Result[0] := S; Exit; end; SepLen := Length(Separator); ALen := Limit; SetLength(Result, ALen); Index := 0; P := PChar(S); while P^ <> #0 do begin F := P; P := AnsiStrPos(P, PChar(Separator)); if (P = nil) or ((Limit > 0) and (Index = Limit - 1)) then P := StrEnd(F); if Index >= ALen then begin Inc(ALen, 5); SetLength(Result, ALen); end; SetString(Result[Index], F, P - F); Inc(Index); if P^ <> #0 then Inc(P, SepLen); end; if Index < ALen then SetLength(Result, Index); end;
Przykładowe użycie:
var res: TStringDynArray; begin res := Explode(':', yourString);
źródło
Napisałem tę funkcję, która zwraca połączoną listę oddzielonych ciągów według określonego separatora. Czysty darmowy pascal bez modułów.
Program split_f; type PTItem = ^TItem; TItem = record str : string; next : PTItem; end; var s : string; strs : PTItem; procedure split(str : string;delim : char;var list : PTItem); var i : integer; buff : PTItem; begin new(list); buff:= list; buff^.str:=''; buff^.next:=nil; for i:=1 to length(str) do begin if (str[i] = delim) then begin new(buff^.next); buff:=buff^.next; buff^.str := ''; buff^.next := nil; end else buff^.str:= buff^.str+str[i]; end; end; procedure print(var list:PTItem); var buff : PTItem; begin buff := list; while buff<>nil do begin writeln(buff^.str); buff:= buff^.next; end; end; begin s := 'Hi;how;are;you?'; split(s, ';', strs); print(strs); end.
źródło
Biblioteka kodów Jedi zapewnia ulepszoną listę StringList z wbudowaną funkcją Split, która może zarówno dodawać, jak i zastępować istniejący tekst. Zapewnia również interfejs zliczany referencyjnie. Więc może to być używane nawet ze starszymi wersjami Delphi, które nie mają SplitStrings i bez starannych i nieco żmudnych dostosowań standardowego TStringList, aby używać tylko określonych separatorów.
Na przykład podany plik tekstowy linii, takich jak
Dog 5 4 7
jeden, można przeanalizować za pomocą:var slF, slR: IJclStringList; ai: TList<integer>; s: string; i: integer; action: procedure(const Name: string; Const Data: array of integer); slF := TJclStringList.Create; slF.LoadFromFile('some.txt'); slR := TJclStringList.Create; for s in slF do begin slR.Split(s, ' ', true); ai := TList<Integer>.Create; try for i := 1 to slR.Count - 1 do ai.Add(StrToInt(slR[i])); action(slR[0], ai.ToArray); finally ai.Free; end; end;
http://wiki.delphi-jedi.org/wiki/JCL_Help:IJclStringList.Split@string@string@Boolean
źródło
To rozwiąże twój problem
interface TArrayStr = Array Of string; implementation function SplitString(Text: String): TArrayStr; var intIdx: Integer; intIdxOutput: Integer; const Delimiter = ';'; begin intIdxOutput := 0; SetLength(Result, 1); Result[0] := ''; for intIdx := 1 to Length(Text) do begin if Text[intIdx] = Delimiter then begin intIdxOutput := intIdxOutput + 1; SetLength(Result, Length(Result) + 1); end else Result[intIdxOutput] := Result[intIdxOutput] + Text[intIdx]; end; end;
źródło
Moja ulubiona funkcja do dzielenia:
procedure splitString(delim: char; s: string; ListOfStrings: TStrings); var temp: string; i: integer; begin ListOfStrings.Clear; for i:=1 to length(s) do begin if s[i] = delim then begin ListOfStrings.add(temp); temp := ''; end else begin temp := temp + s[i]; if i=length(s) then ListOfStrings.add(temp); end; end; ListOfStrings.add(temp); end;
źródło
ListOfStrings.add(temp);
po pętli, aby dodać ostatni element.*
//Basic functionality of a TStringList solves this: uses Classes //TStringList ,types //TStringDynArray ,SysUtils //StringReplace() ; .... //-------------------------------------------------------------------------- function _SplitString(const s:string; const delimiter:Char):TStringDynArray; var sl:TStringList; i:integer; begin sl:=TStringList.Create; //separete delimited items by sLineBreak;TStringlist will do the job: sl.Text:=StringReplace(s,delimiter,sLineBreak,[rfReplaceAll]); //return the splitted string as an array: setlength(Result,sl.count); for i:=0 to sl.Count-1 do Result[i]:=sl[i]; sl.Free; end; //To split a FileName (last item will be the pure filename itselfs): function _SplitPath(const fn:TFileName):TStringDynArray; begin result:=_SplitString(fn,'\'); end;
*
źródło
W bazie odpowiedzi NGLG https://stackoverflow.com/a/8811242/6619626 możesz skorzystać z następującej funkcji:
type OurArrayStr=array of string; function SplitString(DelimeterChars:char;Str:string):OurArrayStr; var seg: TStringList; i:integer; ret:OurArrayStr; begin seg := TStringList.Create; ExtractStrings([DelimeterChars],[], PChar(Str), seg); for i:=0 to seg.Count-1 do begin SetLength(ret,length(ret)+1); ret[length(ret)-1]:=seg.Strings[i]; end; SplitString:=ret; seg.Free; end;
Działa we wszystkich wersjach Delphi.
źródło
W przypadku Delphi 2010 musisz utworzyć własną funkcję podziału.
function Split(const Texto, Delimitador: string): TStringArray; var i: integer; Len: integer; PosStart: integer; PosDel: integer; TempText:string; begin i := 0; SetLength(Result, 1); Len := Length(Delimitador); PosStart := 1; PosDel := Pos(Delimitador, Texto); TempText:= Texto; while PosDel > 0 do begin Result[i] := Copy(TempText, PosStart, PosDel - PosStart); PosStart := PosDel + Len; TempText:=Copy(TempText, PosStart, Length(TempText)); PosDel := Pos(Delimitador, TempText); PosStart := 1; inc(i); SetLength(Result, i + 1); end; Result[i] := Copy(TempText, PosStart, Length(TempText)); end;
Możesz odnieść się do tego jako takiego
type TStringArray = array of string; var Temp2:TStringArray; Temp1="hello:world"; Temp2=Split(Temp1,':')
źródło
procedure SplitCSV(S:STRING;out SL:TStringList); var c,commatext:string; a,b,up:integer; begin c:=s.Replace(' ','<SPACE>'); //curate spaces //first ocurrence of " a:=pos('"',c); b:=pos('"',c,a+1); if (a>0) and (b>0) then begin commatext:=commatext+copy(c,0,a-1); commatext:=commatext+copy(c,a,b-a+1).Replace(',','<COMMA>'); //curate commas up:=b+1; end else commatext:=c; //while continue discovering " while (a>0) and (b>0) do begin a:=Pos('"',c,b+1); b:=pos('"',c,a+1); if (a>0) and (b>0) then begin commatext:=commatext+copy(c,up,a-up); commatext:=commatext+copy(c,a,b-a+1).Replace(',','<COMMA>'); //curate commas up:=b+1; end; end; //last piece of text end if up<c.Length then commatext:=commatext+copy(c,up,c.Length-up+1); //split text using CommaText sl.CommaText:=commatext; sl.Text:=sl.Text.Replace('<COMMA>',','); //curate commas sl.Text:=sl.Text.Replace('<SPACE>',' '); //curate spaces end;
źródło
interface uses Classes; type TStringArray = array of string; TUtilStr = class class function Split(const AValue: string; const ADelimiter: Char = ';'; const AQuoteChar: Char = '"'): TStringArray; static; end; implementation { TUtilStr } class function TUtilStr.Split(const AValue: string; const ADelimiter: Char; const AQuoteChar: Char): TStringArray; var LSplited: TStringList; LText: string; LIndex: Integer; begin LSplited := TStringList.Create; try LSplited.StrictDelimiter := True; LSplited.Delimiter := ADelimiter; LSplited.QuoteChar := AQuoteChar; LSplited.DelimitedText := AValue; SetLength(Result, LSplited.Count); for LIndex := 0 to LSplited.Count - 1 do begin Result[LIndex] := LSplited[LIndex]; end; finally LSplited.Free; end; end; end.
źródło