StrUtils.SplitString无法按预期工作

时间:2016-03-07 09:59:25

标签: delphi delphi-xe2

我使用StrUtils将字符串拆分为TStringDynArray,但输出不符合预期。我将尝试解释这个问题:

我有一个字符串str'a'; 'b'; 'c'
现在我调用StrUtils.SplitString(str, '; ');来分割字符串,我期望一个包含三个元素的数组:'a''b''c'

但我得到的是一个包含五个元素的数组:'a''''b''''c'
当我只用';'而不是'; '进行拆分时,我会得到三个带有前导空格的元素。

那么为什么我在第一个解决方案中得到空字符串?

3 个答案:

答案 0 :(得分:15)

此功能旨在不合并连续的分隔符。例如,考虑在逗号上拆分以下字符串:

foo,,bar

您期望SplitString('foo,,bar', ',')返回什么?您是在寻找('foo', 'bar')还是应该回答('foo', '', 'bar')?它并不清楚先验是正确的,不同的用例可能需要不同的输出。

如果是您的情况,您指定了两个分隔符,';'' '。这意味着

'a'; 'b'

';'分割,再在' '分割。在这两个分隔符之间没有任何内容,因此在'a''b'之间返回一个空字符串。

XE3中引入的Split中的string helper方法具有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;

当然,所有这些都假设您希望空间充当分隔符。您已经在代码中询问了这一点,但实际上您可能只希望;充当分隔符。在这种情况下,您可能希望将';'作为分隔符传递,并修剪返回的字符串。

答案 1 :(得分:14)

SplitString定义为

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

有人会认为Delimiters表示用于拆分字符串的单个分隔符字符串,但它实际上表示用于拆分字符串的单个字符集。 Delimiters字符串中的每个字符都将用作可能的分隔符之一。

SplitString

  

将字符串拆分为由指定分隔的不同部分   分隔符字符。 SplitString将字符串拆分为不同的部分   由指定的分隔符字符分隔。 S是字符串   分裂。分隔符是包含定义为的字符的字符串   分隔符。

答案 2 :(得分:5)

这是因为SplitString的第二个参数是单个字符分隔符的列表,所以&#39 ;; &#39;意味着分裂为&#39 ;;&#39;或拆分为&#39; &#39 ;.所以字符串在每个&#39;;&#39;在每个空间,以及&#39 ;;&#39;而且&#39; &#39;什么都没有,因此是空的。