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 字符串中的每个字符都将用作可能的分隔符之一。

SplitString

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.

的字符串