StrUtils.SplitString 未按预期工作
StrUtils.SplitString not working as expected
我使用 StrUtils
将字符串拆分为 TStringDynArray
,但输出结果与预期不符。我会尝试解释这个问题:
我有一个字符串 str
: 'a'; 'b'; 'c'
现在我调用 StrUtils.SplitString(str, '; ');
来拆分字符串,我希望得到一个包含三个元素的数组:'a'
、'b'
、'c'
但我得到的是一个包含五个元素的数组:'a'
、''
、'b'
、''
、'c'
.
当我只用 ';'
而不是 '; '
拆分时,我得到三个带有前导空格的元素。
那么为什么我的第一个解决方案中得到空字符串?
SplitString
定义为
function SplitString(const S, Delimiters: string): TStringDynArray;
人们会认为Delimiters
表示用于分割字符串的单个分隔符字符串,但实际上它表示用于分割字符串的单个字符集。 Delimiters
字符串中的每个字符都将用作可能的分隔符之一。
Splits a string into different parts delimited by the specified
delimiter characters. SplitString splits a string into different parts
delimited by the specified delimiter characters. S is the string to be
split. Delimiters is a string containing the characters defined as
delimiters.
因为SplitString的第二个参数是一个单字符分隔符列表,所以'; ' 表示在 ';' 处拆分或在 ' ' 处拆分。所以字符串在每个';'处被分割在每个 space 处,以及“;”之间而 ' ' 什么都没有,因此是空字符串。
此功能旨在不合并连续的分隔符。例如,考虑用逗号拆分以下字符串:
foo,,bar
您希望 SplitString('foo,,bar', ',')
到 return 是什么?您是要查找 ('foo', 'bar')
还是应该查找 ('foo', '', 'bar')
?先验并不清楚哪个是正确的,不同的用例可能需要不同的输出。
如果你的情况,你指定了两个分隔符,';'
和 ' '
。这意味着
'a'; 'b'
在 ';'
分裂,然后在 ' '
分裂。在这两个定界符之间没有任何内容,因此在 'a'
和 'b'
.
之间 returned 了一个空字符串
Split
method from the string helper introduced in XE3 has a TStringSplitOptions
参数。如果您为该参数传递 ExcludeEmpty
,则连续的分隔符将被视为单个分隔符。这个程序:
{$APPTYPE CONSOLE}
uses
System.SysUtils;
var
S: string;
begin
for S in '''a''; ''b''; ''c'''.Split([';', ' '], ExcludeEmpty) do begin
Writeln(S);
end;
end.
输出:
'a'
'b'
'c'
但是您在 XE2 中没有此功能,所以我认为您将不得不推出自己的拆分功能。可能看起来像这样:
function IsSeparator(const C: Char; const Separators: string): Boolean;
var
sep: Char;
begin
for sep in Separators do begin
if sep=C then begin
Result := True;
exit;
end;
end;
Result := False;
end;
function Split(const Str, Separators: string): TArray<string>;
var
CharIndex, ItemIndex: Integer;
len: Integer;
SeparatorCount: Integer;
Start: Integer;
begin
len := Length(Str);
if len=0 then begin
Result := nil;
exit;
end;
SeparatorCount := 0;
for CharIndex := 1 to len do begin
if IsSeparator(Str[CharIndex], Separators) then begin
inc(SeparatorCount);
end;
end;
SetLength(Result, SeparatorCount+1); // potentially an over-allocation
ItemIndex := 0;
Start := 1;
CharIndex := 1;
for CharIndex := 1 to len do begin
if IsSeparator(Str[CharIndex], Separators) then begin
if CharIndex>Start then begin
Result[ItemIndex] := Copy(Str, Start, CharIndex-Start);
inc(ItemIndex);
end;
Start := CharIndex+1;
end;
end;
if len>Start then begin
Result[ItemIndex] := Copy(Str, Start, len-Start+1);
inc(ItemIndex);
end;
SetLength(Result, ItemIndex);
end;
当然,所有这些都假定您希望 space 充当分隔符。您已在代码中要求这样做,但也许您实际上只希望 ;
充当分隔符。在那种情况下,您可能希望将 ';'
作为分隔符传递,而 trim 是 returned.
的字符串
我使用 StrUtils
将字符串拆分为 TStringDynArray
,但输出结果与预期不符。我会尝试解释这个问题:
我有一个字符串 str
: 'a'; 'b'; 'c'
现在我调用 StrUtils.SplitString(str, '; ');
来拆分字符串,我希望得到一个包含三个元素的数组:'a'
、'b'
、'c'
但我得到的是一个包含五个元素的数组:'a'
、''
、'b'
、''
、'c'
.
当我只用 ';'
而不是 '; '
拆分时,我得到三个带有前导空格的元素。
那么为什么我的第一个解决方案中得到空字符串?
SplitString
定义为
function SplitString(const S, Delimiters: string): TStringDynArray;
人们会认为Delimiters
表示用于分割字符串的单个分隔符字符串,但实际上它表示用于分割字符串的单个字符集。 Delimiters
字符串中的每个字符都将用作可能的分隔符之一。
Splits a string into different parts delimited by the specified delimiter characters. SplitString splits a string into different parts delimited by the specified delimiter characters. S is the string to be split. Delimiters is a string containing the characters defined as delimiters.
因为SplitString的第二个参数是一个单字符分隔符列表,所以'; ' 表示在 ';' 处拆分或在 ' ' 处拆分。所以字符串在每个';'处被分割在每个 space 处,以及“;”之间而 ' ' 什么都没有,因此是空字符串。
此功能旨在不合并连续的分隔符。例如,考虑用逗号拆分以下字符串:
foo,,bar
您希望 SplitString('foo,,bar', ',')
到 return 是什么?您是要查找 ('foo', 'bar')
还是应该查找 ('foo', '', 'bar')
?先验并不清楚哪个是正确的,不同的用例可能需要不同的输出。
如果你的情况,你指定了两个分隔符,';'
和 ' '
。这意味着
'a'; 'b'
在 ';'
分裂,然后在 ' '
分裂。在这两个定界符之间没有任何内容,因此在 'a'
和 'b'
.
Split
method from the string helper introduced in XE3 has a TStringSplitOptions
参数。如果您为该参数传递 ExcludeEmpty
,则连续的分隔符将被视为单个分隔符。这个程序:
{$APPTYPE CONSOLE}
uses
System.SysUtils;
var
S: string;
begin
for S in '''a''; ''b''; ''c'''.Split([';', ' '], ExcludeEmpty) do begin
Writeln(S);
end;
end.
输出:
'a' 'b' 'c'
但是您在 XE2 中没有此功能,所以我认为您将不得不推出自己的拆分功能。可能看起来像这样:
function IsSeparator(const C: Char; const Separators: string): Boolean;
var
sep: Char;
begin
for sep in Separators do begin
if sep=C then begin
Result := True;
exit;
end;
end;
Result := False;
end;
function Split(const Str, Separators: string): TArray<string>;
var
CharIndex, ItemIndex: Integer;
len: Integer;
SeparatorCount: Integer;
Start: Integer;
begin
len := Length(Str);
if len=0 then begin
Result := nil;
exit;
end;
SeparatorCount := 0;
for CharIndex := 1 to len do begin
if IsSeparator(Str[CharIndex], Separators) then begin
inc(SeparatorCount);
end;
end;
SetLength(Result, SeparatorCount+1); // potentially an over-allocation
ItemIndex := 0;
Start := 1;
CharIndex := 1;
for CharIndex := 1 to len do begin
if IsSeparator(Str[CharIndex], Separators) then begin
if CharIndex>Start then begin
Result[ItemIndex] := Copy(Str, Start, CharIndex-Start);
inc(ItemIndex);
end;
Start := CharIndex+1;
end;
end;
if len>Start then begin
Result[ItemIndex] := Copy(Str, Start, len-Start+1);
inc(ItemIndex);
end;
SetLength(Result, ItemIndex);
end;
当然,所有这些都假定您希望 space 充当分隔符。您已在代码中要求这样做,但也许您实际上只希望 ;
充当分隔符。在那种情况下,您可能希望将 ';'
作为分隔符传递,而 trim 是 returned.