2008-09-26 89 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西雅圖。