【问题标题】:How to concatenate array of string elements into a string如何将字符串元素数组连接成字符串
【发布时间】:2015-05-10 20:12:10
【问题描述】:

字符串数组应该如何转换成字符串(带分隔符)?我的意思是,我可以使用一些系统函数来代替自己编写函数吗?

【问题讨论】:

  • 什么Delphi版本?
  • @KenWhite:版本是Delphi2007
  • 您可以使用带分隔符的 TStringList。或者你可以编写你自己的函数。我会避开 TStringList。无需为此创建实例。

标签: arrays string delphi string-concatenation delphi-2007


【解决方案1】:

由于您使用的是 Delphi 2007,您必须自己动手:

function StrArrayJoin(const StringArray : array of string; const Separator : string) : string;
var
  i : Integer;
begin
  Result := '';
  for i := low(StringArray) to high(StringArray) do
    Result := Result + StringArray[i] + Separator;

  Delete(Result, Length(Result), 1);
end;

只需遍历数组并将其与您的分隔符连接起来。

还有一个小测试示例:

procedure TForm1.FormCreate(Sender: TObject);
begin
  Caption :=StrArrayJoin(['This', 'is', 'a', 'test'], ' ');
end;

【讨论】:

  • 我自己写了函数!感谢您的建议!
  • 在速度方面并不理想
  • 但是对于那些对 Delphi 和指针不太熟悉的人来说,可读且易于理解
【解决方案2】:

如果您使用的是较新版本的 Delphi,您可以使用 TStringHelper.Join,请参阅:http://docwiki.embarcadero.com/Libraries/Sydney/en/System.SysUtils.TStringHelper.Join

Writeln(String.Join(',', ['String1', 'String2', 'String3']));

输出将是:String1,String2,String3

【讨论】:

    【解决方案3】:

    接受的答案在速度方面并不理想,尤其是在使用多个线程的情况下。这种方法在单核上的速度提高了 3 倍,并且可以在 SMP 上很好地扩展。

    function JoinStrings(const s: array of string; Delimiter: Char): string;
    var
      i, c: Integer;
      p: PChar;
    begin
      c := 0;
      for i := 0 to High(s) do
        Inc(c, Length(s[i]));
      SetLength(Result, c + High(s));
      p := PChar(Result);
      for i := 0 to High(s) do begin
        if i > 0 then begin
          p^ := Delimiter;
          Inc(p);
        end;
        Move(PChar(s[i])^, p^, SizeOf(Char)*Length(s[i]));
        Inc(p, Length(s[i]));
      end;
    end;
    

    速度测试:

    program Project1;
    
    {$APPTYPE CONSOLE}
    
    uses
      Windows, SysUtils, StrUtils, Classes;
    
    function StrArrayJoin(const StringArray: array of string; const Separator: string) : string;
    var
      i : Integer;
    begin
      Result := '';
      for i := low(StringArray) to high(StringArray) do
        Result := Result + StringArray[i] + Separator;
      Delete(Result, Length(Result), 1);
    end;
    
    function JoinStrings(const s: array of string; Delimiter: Char): string;
    var
      i, c: Integer;
      p: PChar;
    begin
      c := 0;
      for i := 0 to High(s) do
        Inc(c, Length(s[i]));
      SetLength(Result, c + High(s));
      p := PChar(Result);
      for i := 0 to High(s) do begin
        if i > 0 then begin
          p^ := Delimiter;
          Inc(p);
        end;
        Move(PChar(s[i])^, p^, SizeOf(Char)*Length(s[i]));
        Inc(p, Length(s[i]));
      end;
    end;
    
    var
      TestData: array of string;
    
    type
      TTestThread = class(TThread)
      protected
        Func: Boolean;
        Count: Integer;
        procedure Execute; override;
      end;
    
    procedure TTestThread.Execute;
    var
      dtStart: TDateTime;
      i: Integer;
    begin
      dtStart := Now;
      Count := 0;
      repeat
        for i := 1 to 1000 do
          if Func then
            JoinStrings(TestData, ';')
          else
            StrArrayJoin(TestData, ';');
        InterlockedIncrement(Count);
      until Now > dtStart + 1/86400;
    end;
    
    procedure TestSmp(CpuCount: Integer; Func: Boolean);
    var
      i, c: Integer;
      Threads: array of TTestThread;
    begin
      SetLength(Threads, CpuCount);
      for i := 0 to High(Threads) do begin
        Threads[i] := TTestThread.Create(true);
        Threads[i].Func := Func;
        Threads[i].Resume;
      end;
      c := 0;
      for i := 0 to High(Threads) do begin
        Threads[i].WaitFor;
        Inc(c, Threads[i].Count);
        Threads[i].Free;
      end;
      WriteLn(c);
    end;
    
    procedure Init();
    var
      i: Integer;
    begin
      SetLength(TestData, 1000);
      for i := 0 to High(TestData) do
        TestData[i] := DupeString('x', Random(32));
    end;
    
    begin
      try
        Init();
        Assert(StrArrayJoin(TestData, ';') = JoinStrings(TestData, ';'));
        TestSmp(1, false);
        TestSmp(1, true);
        TestSmp(4, false);
        TestSmp(4, true);
      except
        on E:Exception do
          Writeln(E.Classname, ': ', E.Message);
      end;
      Readln;
    end.
    

    结果:在四核 CPU 上,JoinStrings 的速度提高了 12 倍。

    StrArrayJoin 1 thread:  55
    JoinStrings  1 thread:  184
    StrArrayJoin 4 threads: 58
    JoinStrings  4 threads: 713
    

    【讨论】:

      【解决方案4】:

      在delphi for .NET中你可以使用框架Join函数,如果你不想依赖.NET框架那么你可以链接开源JCL库:看看IJclStringList interface图书馆的。

      JclStringList.Join(',');
      

      否则,正如 cmets 中有人建议的那样,您可以通过这种方式简单地使用 TStringList :

      arrayList.Delimiter := ',';
      arrayList.QuoteChar := '';
      joinedArray := arrayList.DelimitedText;
      

      请注意,最新版本的 Delphi XEs(如果我记得很清楚,是从 XE3 开始)有一个 TStringHelper 类,它将 Join 方法添加到 String 类: p>

       class function Join(const Separator: string; const Values: 
      IEnumerator<string>): string; overload; static;
      

      【讨论】:

      • 您需要接受string 的开放数组的Join 重载。当然,Join 作为字符串助手的一部分,实现得非常糟糕。 IEnumerable&lt;string&gt;版本破解到XE8,效率差。令人沮丧的是,Emba 最近的 RTL 质量如此糟糕。
      • 实际上将 QuoteChar 设置为 '' 应该不起作用(至少在 Delphi 11 中,在执行 TStringList.Create 时似乎不支持它)。必须改用空字符(又名 #0)。见docwiki.embarcadero.com/Libraries/Sydney/en/…
      猜你喜欢
      • 1970-01-01
      • 2014-11-04
      • 1970-01-01
      • 2020-04-02
      • 1970-01-01
      • 2016-01-25
      • 2013-02-04
      • 2021-10-05
      • 2023-04-02
      相关资源
      最近更新 更多