2008-09-26 147 views
9

我使用StringReplace替换& GT和& LT由焦炭本身在生成的XML是这样的:StringReplace的替代品,以提高性能

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

的事情是它需要的方式tooo长替换的每一次出现& gt。

你有什么更好的主意让它更快吗?

+0

你可以得到任何关于原始代码Spul vs. Jorge的代码与FastStrings的反馈吗? – gabr 2008-09-27 06:49:01

+0

StringReplace的问题是当您有多个需要替换的事件时。在这种情况下,你应该编写自己的版本,类似于Gabr发布的版本。实际上这个问题不是调用StringReplace 2次,而是让它处理几十个替换。 – 2011-09-08 19:20:48

回答

2

的问题是,你迭代整个字符串大小的两倍(一个用于替换& GT;可以通过>和另一个替换& lt;通过<)。

你应该迭代一个for,只要你找到一个&就可以检查一下GT;或lt;并立即替换,然后跳过3个字符((g | l)t;)。通过这种方式,它可以在比例的时间内对字符串xml.Text的大小进行处理。


一个简单的C#示例,因为我不知道德尔福,但应该为你做的一般想法。

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> 
+0

问题不是迭代字符串两次,而是让它处理许多替换。对于不同的字符串,调用它两次或更多是没有问题的,如果实现它与RTL中的方式不同,则替换它。 – 2011-09-08 19:22:31

2

由豪费雷拉写入的C#代码的未测试的转换。

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; 
+0

这是保存为Unicode吗? – 2008-09-26 16:56:46

2

Systools(Turbopower,现在开源)有一个ReplaceStringAllL函数,它可以在字符串中执行所有这些函数。

8

如果您使用的是Delphi 2009,那么使用TStringBuilder比使用ReplaceString快3倍。它也是Unicode安全的。

我使用的文本从http://www.CodeGear.com与变更为"&lt;""&gt;"作为我的出发点的“<”和“>”所有事件。

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

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; 
6

你一定要看看Fastcode项目网页:http://fastcode.sourceforge.net/

他们跑了挑战为了更快的StringReplace(Ansi StringReplace挑战),“赢家”比Delphi RTL快14倍。

几个fastcode函数已经包含在Delphi本身的最新版本中(我认为D2007),所以根据你使用的是哪个Delphi版本,性能改进可能会有很大的不同。

如前所述,如果您认真对待处理XML,您应该真的在寻找基于Unicode的解决方案。

1

当您处理多行文本文件时,您可以通过逐行处理获得一些性能。在我的测试中,这种方法将大约90%的时间减少到大于1MB xml文件的进程替换。

procedure ReplaceMultilineString(xml: TStrings); 
var 
    i: Integer; 
    line: String; 
begin 
    for i:=0 to xml.Count-1 do 
    begin 
    line := xml[i]; 
    line := StringReplace(line, '&gt;', '>', [rfReplaceAll]); 
    line := StringReplace(line, '&lt;', '<', [rfReplaceAll]); 
    xml[i] := line; 
    end; 
end; 

注:德尔福10西雅图。