根据分隔符将字符串拆分为字符串数组

时间:2010-04-12 21:49:38

标签: delphi string split delimiter

我正在尝试找到一个Delphi函数,它将输入字符串拆分为基于分隔符的字符串数组。我在谷歌上找到了很多,但似乎都有自己的问题,而且我无法让它们发挥作用。

我只需要分割一个字符串,如: "word:doc,txt,docx"基于':'进入数组。结果将是 ['word', 'doc,txt,docx']

有没有人有他们知道的功能?

谢谢

20 个答案:

答案 0 :(得分:76)

您可以使用TStrings.DelimitedText属性拆分字符串

检查此示例

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.

更新

有关StrictDelimiter的解释,请参阅此link

答案 1 :(得分:59)

无需设计Split功能。它已经存在,请参阅:Classes.ExtractStrings

以下列方式使用它:

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.

完全回答这个问题; List表示包含元素的所需数组:

List[0] = 'word'
List[1] = 'doc,txt,docx'

答案 2 :(得分:41)

您可以使用StrUtils.SplitString

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

来自documentation

的描述
  

将字符串拆分为由指定分隔的不同部分   分隔符。

     

SplitString 将字符串拆分为由指定的分隔符分隔的不同部分。 S 是要拆分的字符串。   分隔符是一个字符串,其中包含定义为分隔符的字符。

     

SplitString 返回类型System.Types.TStringDynArray的字符串数组,其中包含分割部分   原始字符串。

答案 3 :(得分:35)

使用Delphi XE3中引入的SysUtils.TStringHelper.Split函数:

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

这会将带有给定分隔符的字符串拆分为字符串数组。

答案 4 :(得分:14)

我总是使用类似的东西:

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;

答案 5 :(得分:13)

与Mef提供的爆炸()功能类似,但有一些差异(其中一个我认为是错误修复):

  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;

的差异:

  1. aMax参数限制要返回的字符串数
  2. 如果输入字符串被分隔符终止,则认为名义上的“空”最终字符串存在
  3. 示例:

    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
    

    我认为错误修复是尾随分隔符和名义上的“空最终元素”。

    我还结合了我建议的内存分配更改,并进行了细化(我错误地建议输入字符串最多可能包含50%的分隔符,但可以想象当然包含100%分隔符字符串,产生一个空元素数组! )

答案 6 :(得分:7)

爆炸是一种非常高速的功能,源代码来自TStrings组件。 我使用下一个测试爆炸: 爆炸134217733字节的数据,我得到19173962个元素,工作时间:2984毫秒。

Implode是一种非常低速的功能,但我写得很容易。

{ ****************************************************************************** }
{  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 :(得分:7)

var  
    su  : string;        // What we want split
    si  : TStringList;   // Result of splitting
    Delimiter : string;
    ...
    Delimiter := ';';
    si.Text := ReplaceStr(su, Delimiter, #13#10);

si 列表中的行将包含拆分字符串。

答案 8 :(得分:6)

你可以创建自己的函数,返回字符串TArray:

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;

答案 9 :(得分:5)

我编写了这个函数,它通过特定的分隔符返回分隔字符串的链表。没有模块的纯净自由帕斯卡。

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.

答案 10 :(得分:5)

Here是一个爆炸函数的实现,它作为标准函数在许多其他编程语言中可用:

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; 

样本用法:

var
  res: TStringDynArray;
begin
  res := Explode(':', yourString);

答案 11 :(得分:3)

这将解决您的问题

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;

答案 12 :(得分:3)

Jedi代码库提供了一个增强的StringList,内置了Split函数,能够添加和替换现有文本。它还提供引用计数接口。因此,即使对于没有SplitStrings的旧版Delphi版本,也可以使用这个版本,并且没有仔细和有点繁琐的库存TStringList自定义,只能使用指定的分隔符。

例如给定Dog 5 4 7之类行的文本文件,可以使用以下方法解析它们:

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

答案 13 :(得分:1)

我最喜欢的分切功能:

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;

答案 14 :(得分:0)

*

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

*

答案 15 :(得分:0)

NGLG回答https://stackoverflow.com/a/8811242/6619626的基础您可以使用以下功能:

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;

适用于所有Delphi版本。

答案 16 :(得分:0)

对于delphi 2010,您需要创建自己的分割功能。

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;

你可以这样称呼

type
  TStringArray = array of string;
var Temp2:TStringArray;
Temp1="hello:world";
Temp2=Split(Temp1,':')

答案 17 :(得分:0)

<form name="payForm" method="post" action="https://www.siampay.com/eng/payment/payForm.jsp">
    <input type="submit" name="submit" value="Buy">
    <input type="number" name="amount" value="" placeholder="Enter amount in THB ">
    <input type="hidden" name="merchantId" value="76117579">
    <input type="hidden" name="orderRef" value="76117579">
    <input type="hidden" name="currCode" value="764" >
    <input type="hidden" name="successUrl" value="">
    <input type="hidden" name="failUrl" value="">
    <input type="hidden" name="cancelUrl" value="">
    <input type="hidden" name="remark" value="">
    <input type="hidden" name="lang" value="E">
</form>

答案 18 :(得分:0)

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.

答案 19 :(得分:0)

我最初赞扬了@Frank 的回答,因为我需要一些适用于 Delphi 6 的东西并且它似乎有效。但是,此后我发现该解决方案存在一个错误,即无论分隔符如何,它仍会在 #13#10 上拆分。如果您不希望在源字符串中出现行,则可以完美运行。

我写了一个简单的解析器,它只适用于单字符分隔符。注意:它将值放入 TStrings 中,而不是按照操作要求放入数组中,但可以轻松修改以适应数组。

流程如下:

procedure SplitString(const ASource: string; const ADelimiter: Char; AValues: TStrings);
var
  i, lastDelimPos: Integer;
begin
  AValues.Clear;
  lastDelimPos := 0;

  for i := 1 to Length(ASource) do
    if ASource[i] = ADelimiter then
    begin
      if lastDelimPos = 0 then
        AValues.Add(CopyRange(ASource, 1, i - 1))
      else
        AValues.Add(CopyRange(ASource, lastDelimPos + 1, i - 1));
      lastDelimPos := i;
    end;

  if lastDelimPos = 0 then
    AValues.Add(ASource)
  else
    AValues.Add(CopyRange(ASource, lastDelimPos + 1, MaxInt));
end;

function CopyRange(const s: string; const AIndexFrom, AIndexTo: Integer): string;
begin
  Result := Copy(s, AIndexFrom, AIndexTo - AIndexFrom + 1);
end;

注意:根据 C# 的 string.Split(),空白输入字符串将导致 TStrings 中的单个空白字符串。类似地,仅将分隔符作为输入字符串会导致 TStrings 中出现两个空白字符串。

这是我用来确保它可靠的粗略测试代码:

procedure AddTest(const ATestLine: string; const AExpectedResult: array of string);
var
  expectedResult: TStringList;
  i: Integer;
begin
  expectedResult := TStringList.Create;
  for i := 0 to Length(AExpectedResult) - 1 do
    expectedResult.Add(AExpectedResult[i]);
  testStrings.AddObject(ATestLine, expectedResult);
end;

//====================

AddTest('test', ['test']);
AddTest('', ['']);
AddTest(',', ['', '']);
AddTest('line1' + #13#10 + ',line 2,line3, line 4', ['line1' + #13#10, 'line 2', 'line3', ' line 4']);
AddTest('line1' + #13#10 + 'd,line 2,line3, line 4', ['line1' + #13#10 + 'd', 'line 2', 'line3', ' line 4']);
AddTest('line1,line 2,line3, line 4', ['line1', 'line 2', 'line3', ' line 4']);
AddTest('test, ', ['test', ' ']);
AddTest('test,', ['test', '']);
AddTest('test1,test2 ', ['test1', 'test2 ']);
AddTest('test1,test2', ['test1', 'test2']);
AddTest('test1,test2, ', ['test1', 'test2', ' ']);
AddTest('test1,test2,', ['test1', 'test2', '']);

//====================

testFailed := False;
for i := 0 to testStrings.Count - 1 do
begin
  SplitString2(testStrings[i], ',', f);
  log('Test ID=%d', [i]);
  log('    Test String="%s"', [testStrings[i]]);
  log('    Item count=%d', [f.Count]);
  testResult := TStringList(TestStrings.Objects[i]);
  if testResult.Count <> f.Count then
  begin
    Log('!!');
    Log('!! Count mismatch. Got=%d, Expected=%d', [f.Count, testResult.Count]);
    Log('!!');

    testFailed := True;
  end;

  for j := 0 to f.Count - 1 do
  begin
    log('    Item %d="%s"    (len=%d)', [j, f[j], Length(f[j])]);
    if testResult[j] <> f[j] then
    begin
      Log('!!');
      Log('!! Text mismatch. Got="%s", Expected="%s"', [f[j], testResult[j]]);
      Log('!!');

      testFailed := True;
    end;
  end;
end;

编辑:缺少 CopyRange() 函数的代码,现在添加。我的错。