StringReplace替代品以提高性能

时间:2020-03-06 14:47:13  来源:igfitidea点击:

我正在使用StringReplace在生成的XML中用char本身替换&gt和&lt,如下所示:

StringReplace(xml.Text,'>','>',[rfReplaceAll]) ;
StringReplace(xml.Text,'&lt;','<',[rfReplaceAll]) ;

事实是,替换&gt的每次出现都花了很长时间。

我们是否有更好的主意来加快速度?

解决方案

问题是我们要遍历整个字符串大小两次(一个用于将>替换为>,另一个用于将<替换为<)。

我们应该以for进行迭代,并且只要找到&for gt就简单地进行检查。或者lt;并立即替换,然后跳过3个字符((g | l)t;)。这样,它可以在与字符串xml.Text的大小成比例的时间内完成此操作。

一个简单的Cexample,因为我不了解Delphi,但应该为我们提供一个大致的思路。

String s = "&lt;xml&gt;test&lt;/xml&gt;";
char[] input = s.ToCharArray();
char[] res = new char[s.Length];
int j = 0;
for (int i = 0, count = input.Length; i < count; ++i)
{
    if (input[i] == '&')
    {
        if (i < count - 3)
        {
            if (input[i + 1] == 'l' || input[i + 1] == 'g')
            {
                if (input[i + 2] == 't' && input[i + 3] == ';')
                {
                    res[j++] = input[i + 1] == 'l' ? '<' : '>';
                    i += 3;
                    continue;
                }
            }
        }
    }

    res[j++] = input[i];
}
Console.WriteLine(new string(res, 0, j));

输出:

<xml>test</xml>

Jorge Ferreira编写的Ccode的未经测试的转换。

function ReplaceLtGt(const s: string): string;
var
  inPtr, outPtr: integer;
begin
  SetLength(Result, Length(s));
  inPtr := 1;
  outPtr := 1;
  while inPtr <= Length(s) do begin
    if (s[inPtr] = '&') and ((inPtr + 3) <= Length(s)) and
       (s[inPtr+1] in ['l', 'g']) and (s[inPtr+2] = 't') and
       (s[inPtr+3] = ';') then
    begin
      if s[inPtr+1] = 'l' then
        Result[outPtr] :=  '<'
      else
        Result[outPtr] := '>';
      Inc(inPtr, 3);
    end
    else begin
      Result[outPtr] := Result[inPtr];
      Inc(inPtr);
    end;
    Inc(outPtr);
  end;
  SetLength(Result, outPtr - 1);
end;

尝试使用Peter Morris的FastStrings.pas。

Systools(Turbopower,现在为开放源代码)具有一个ReplaceStringAllL函数,该函数以字符串形式执行所有操作。

如果我们使用的是Delphi 2009,那么使用TStringBuilder进行此操作的速度大约比使用ReplaceString快3倍。这也是Unicode安全的。

我使用来自http://www.CodeGear.com的文本,将所有出现的" <"和">"都更改为"" <"和">"作为起点。

包括字符串分配和创建/释放对象,这些分别在我的系统上分别花费了25毫秒和75毫秒:

function TForm1.TestStringBuilder(const aString: string): string;
var
  sb: TStringBuilder;
begin
  StartTimer;
  sb := TStringBuilder.Create;
  sb.Append(aString);
  sb.Replace('&gt;', '>');
  sb.Replace('&lt;', '<');
  Result := sb.ToString();
  FreeAndNil(sb);
  StopTimer;
end;

function TForm1.TestStringReplace(const aString: string): string;
begin
  StartTimer;
  Result := StringReplace(aString,'&gt;','>',[rfReplaceAll]) ;
  Result := StringReplace(Result,'&lt;','<',[rfReplaceAll]) ;
  StopTimer;
end;

我们绝对应该看一下Fastcode项目页面:http://fastcode.sourceforge.net/

他们面临更快的StringReplace挑战(Ansi StringReplace挑战),而"胜利者"的速度是Delphi RTL的14倍。

在最新版本(我认为是D2007版本)中,Delphi本身已包含几个fastcode函数,因此,性能的改进可能会因所使用的Delphi版本不同而有很大差异。

如前所述,如果我们认真对待XML,那么我们应该真正考虑基于Unicode的解决方案。