Fendre une chaîne en un tableau de chaînes basé sur un délimiteur

j'essaie de trouver une fonction Delphi qui divisera une chaîne de caractères en un tableau de chaînes basé sur un délimiteur. J'ai trouvé beaucoup de choses sur Google, mais tous semblent avoir leurs propres problèmes et je n'ai pas été en mesure d'obtenir l'un d'eux pour travailler.

j'ai juste besoin de fendre une chaîne comme: "word:doc,txt,docx" dans un tableau basé sur les ':'. Le résultat serait ['word', 'doc,txt,docx'] .

est-ce que quelqu'un a une fonction dont il sait qu'elle fonctionne?

Merci

73
demandé sur bluish 2010-04-13 01:49:38

17 réponses

vous pouvez utiliser les TStrings.Propriété DelimitedText pour séparer une chaîne de caractères

vérifier cet échantillon

program Project28;

{$APPTYPE CONSOLE}

uses
  Classes,
  SysUtils;

procedure Split(Delimiter: Char; Str: string; ListOfStrings: TStrings) ;
begin
   ListOfStrings.Clear;
   ListOfStrings.Delimiter       := Delimiter;
   ListOfStrings.StrictDelimiter := True; // Requires D2006 or newer.
   ListOfStrings.DelimitedText   := Str;
end;


var
   OutPutList: TStringList;
begin
   OutPutList := TStringList.Create;
   try
     Split(':', 'word:doc,txt,docx', OutPutList) ;
     Writeln(OutPutList.Text);
     Readln;
   finally
     OutPutList.Free;
   end;
end.

UPDATE

voir ce lien pour une explication de StrictDelimiter .

76
répondu RRUZ 2017-05-23 12:02:59

il n'est pas nécessaire de concevoir une fonction Split . Il existe déjà, voir: Classes.ExtractStrings .

utilisez - le de la manière suivante:

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.

et pour répondre pleinement à la question; List représente le tableau désiré avec les éléments:

List[0] = 'word'
List[1] = 'doc,txt,docx'
58
répondu NGLN 2012-01-10 22:16:28

vous pouvez utiliser StrUtils.SplitString .

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

sa description tirée de la documentation :

Divise une chaîne en différentes parties délimitées par la les caractères délimiteurs.

SplitString divise une chaîne de caractères en différentes parties délimitées par les caractères de délimitation spécifiés. S est la chaîne à split. délimiteurs est une chaîne contenant les caractères définis comme délimiteurs.

SplitString retourne un tableau de chaînes de type système.Type.TStringDynArray qui contient les parties une ficelle originale.

35
répondu alex 2018-09-11 07:45:15

utilisant le SysUtils.TStringHelper.Split fonction, introduit dans Delphi XE3:

var
  MyString: String;
  Splitted: TArray<String>;
begin
  MyString := 'word:doc,txt,docx';
  Splitted := MyString.Split([':']);
end.

cela divisera une chaîne avec un délimiteur donné en un tableau de chaînes.

30
répondu LU RD 2015-04-09 09:03:31

similaire à la fonction Explode () offerte par Mef, mais avec quelques différences (dont une que je considère comme une correction de bug):

  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;

différences:

  1. paramètre aMax limite le nombre de chaînes à retourner
  2. si la chaîne de caractères d'entrée est terminée par un séparateur, alors une chaîne de caractères finale "vide" nominale est réputée exister

exemples:

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

c'est le séparateur de fuite et l '"élément final vide" que je considère comme la correction de bug.

j'ai aussi intégré le changement d'allocation de mémoire que j'ai suggéré, avec un raffinement (j'ai suggéré par erreur que la chaîne de saisie pourrait au plus contenir des séparateurs de 50%, mais elle pourrait se composer naturellement de chaînes de séparateurs de 100%, donnant un tableau d'éléments vides!)

13
répondu Deltics 2010-04-13 04:33:10

j'utilise toujours quelque chose de similaire à ceci:

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;
13
répondu Frank 2010-04-13 09:02:48

Explode est une fonction à très grande vitesse, source alhoritm obtenir du composant TStrings. Je utiliser le test suivant pour exploser: Exploser 134217733 octets de données, j'obtiens 19173962 éléments, le temps de travail: 2984 mme.

Implode est fonction de vitesse très faible, mais je l'écris facile.

{ ****************************************************************************** }
{  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;
7
répondu Delphi 7 2012-04-19 16:47:21
var  
    su  : string;        // What we want split
    si  : TStringList;   // Result of splitting
    Delimiter : string;
    ...
    Delimiter := ';';
    si.Text := ReplaceStr(su, Delimiter, #13#10);

Lignes si liste contiendra coupée en deux chaînes.

7
répondu Ihor Konovalenko 2015-07-08 11:22:14

Ici est une mise en œuvre d'un exploser en fonction de ce qui est disponible dans de nombreux autres langages de programmation comme une fonction standard:

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; 

exemple d'utilisation:

var
  res: TStringDynArray;
begin
  res := Explode(':', yourString);
5
répondu Leo 2010-04-12 21:59:12

vous pouvez faire votre propre fonction qui retourne TArray de chaîne:

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;
5
répondu bob_saginowski 2014-05-17 11:27:22

j'ai écrit cette fonction qui renvoie la liste de chaînes séparées par un délimiteur. Pascal pur et libre sans modules.

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.
5
répondu Aleš Oskar Kocur 2014-05-22 05:33:53

Cela permettra de résoudre votre problème

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;
3
répondu Dennis 2015-01-30 09:57:09
La bibliothèque de codes Jedi

fournit une liste de chaînes améliorée avec fonction de division intégrée, qui est capable à la fois d'ajouter et de remplacer le texte existant. Il fournit également l'interface de référence-compté. Ainsi, cela peut être utilisé même avec les versions Delphi plus anciennes qui n'ont pas de fentes et sans personnalisations soigneuses et fastidieuses de TStringList stock pour n'utiliser que des délimiteurs spécifiés.

par exemple un fichier texte donné de lignes comme Dog 5 4 7 on peut les analyser en utilisant:

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

2
répondu Arioch 'The 2013-01-22 09:03:31

La base de NGLG réponse https://stackoverflow.com/a/8811242/6619626 vous pouvez utiliser la fonction suivante:

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;

fonctionne dans toutes les versions Delphi.

1
répondu Reza Mousavi 2017-12-15 15:21:29

ma fonction préférée pour l'élingage:

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];
        end;
    end;
end;
1
répondu user1141649 2018-09-22 08:06:36

*

//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;

*

0
répondu David Ulbrich 2017-01-20 22:38:36

pour delphi 2010,vous devez créer votre propre fonction split.

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;

vous pouvez l'appeler comme tel

type
  TStringArray = array of string;
var Temp2:TStringArray;
Temp1="hello:world";
Temp2=Split(Temp1,':')
0
répondu user3609960 2018-05-16 21:01:03