在Delphi中将字符串拆分为固定长度的快速方法

Alo*_*mer 4 delphi delphi-2006

我需要将字符串拆分为具有固定长度子字符串的TStringList.

目前我使用:

procedure StrToStringList(ASource: string; AList: TStrings; AFixedLen: Integer);
begin
    Assert(Assigned(AList));
    while Length(ASource) > AFixedLen do
    begin
        AList.Add(LeftStr(ASource, AFixedLen));
        Delete(ASource, 1, AFixedLen);
    end;
    AList.Add(ASource);
end;
Run Code Online (Sandbox Code Playgroud)

这有效,但似乎很慢.有更好/更快的想法吗?

编辑:结果分析:

速度提升令人印象深刻.以下是我(主观)剖析的结果.

数据大小:290KB,FixedLen:100:

  • 原始代码:58毫秒
  • 赫弗南:1毫秒
  • Deltics:1毫秒

数据大小:2805KB,FixedLen:100:

  • 原始代码:5803毫秒
  • 赫弗南:5毫秒
  • Deltics:4毫秒

Dav*_*nan 7

我认为修改输入字符串是浪费的.避免这样这样:

var
  Remaining: Integer;
  StartIndex: Integer;
begin
  Remaining := Length(ASource);
  StartIndex := 1;
  while Remaining > 0 do
  begin
    AList.Add(Copy(ASource, StartIndex, AFixedLen));
    inc(StartIndex, AFixedLen);
    dec(Remaining, AFixedLen);
  end;
end;
Run Code Online (Sandbox Code Playgroud)

这将减少堆分配和复制的数量.

但是,如果你观察到性能上没什么好处,我也不会感到惊讶.为了执行任何严肃的优化,我们可能需要查看一些示例输入数据.


Del*_*ics 5

您的代码中可能会立即显示一些明显的优化:

  1. 不要修改源字符串,只需提取所需的子字符串.然后,您可以使输入字符串参数为const,从而允许编译器进一步优化对该过程的调用

  2. 由于您正在处理固定长度和已知长度的输入字符串,因此您可以预先计算字符串列表所需的容量,并在添加列表时避免重新分配内存.

以下是我将如何做到这一点:

procedure StrToStringList(const aSource: String;
                          const aList: TStrings;
                          const aFixedLen: Integer);
var
  idx: Integer;
  srcLen: Integer;
begin
  aList.Capacity := (Length(aSource) div aFixedLen) + 1;

  idx    := 1;
  srcLen := Length(aSource);

  while idx <= srcLen do
  begin
    aList.Add(Copy(aSource, idx, aFixedLen));
    Inc(idx, aFixedLen);
  end;
end;
Run Code Online (Sandbox Code Playgroud)

这里的容量计算可能导致容量过剩1,其中输入字符串精确地除以固定长度,但这是一个可忽略的开销,并且在目标是最佳性能的情况下是可接受的(替代方案是修改或计算的条件分支)容量不同,以满足可能少数情况下的情况).