How should an array of string be converted into string (With separator char)? I mean, is there some system function I can use instead of writing my own function?
Since you are using Delphi 2007 you have to do it you self:
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;
Simply traverse the array and concat it with your seperator.
And a small test example:
procedure TForm1.FormCreate(Sender: TObject);
begin
Caption :=StrArrayJoin(['This', 'is', 'a', 'test'], ' ');
end;
if (Length(Result)>0) then Delete(Result, 1 + Length(Result) - Length(Separator), Length(Separator));
Why didn't anyone notice this before? 🤦 at least 9 people have this bug. –
Fealty If you're using a more recent version of Delphi you could use TStringHelper.Join
, see: http://docwiki.embarcadero.com/Libraries/Sydney/en/System.SysUtils.TStringHelper.Join
Writeln(String.Join(',', ['String1', 'String2', 'String3']));
Output would be: String1,String2,String3
The accepted answer is not ideal in terms of speed, especially if multiple threads are used. This approach is 3x faster on single core, and scales well on 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;
Speed test:
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.
Results: on a quad-core CPU JoinStrings is 12x faster.
StrArrayJoin 1 thread: 55
JoinStrings 1 thread: 184
StrArrayJoin 4 threads: 58
JoinStrings 4 threads: 713
In delphi for .NET you can use the framework Join function , while if you don't want to rely on the .NET framework then you can link the open source JCL library : take a look at the IJclStringList interface of the library .
JclStringList.Join(',');
Otherwise as someone suggested in comments you can simply use a TStringList this way :
arrayList.Delimiter := ',';
arrayList.QuoteChar := '';
joinedArray := arrayList.DelimitedText;
Note that latest version of Delphi XEs(since XE3 if I well remember) have a TStringHelper class that adds the Join method to the String class :
class function Join(const Separator: string; const Values:
IEnumerator<string>): string; overload; static;
Join
overload that accepts an open array of string
. Of course, Join
, being part of the string helper, is implemented very poorly. The IEnumerable<string>
version is broken until XE8, and the efficiency is poor. It's frustrating that Emba's recent RTL quality is so poor. –
Larimor © 2022 - 2024 — McMap. All rights reserved.