2008-09-26 9 views
9

I StringReplace bin mit & gt und & lt durch das Zeichen selbst in einer dynamisch erzeugten XML wie folgt zu ersetzen:StringReplace Alternativen zur Verbesserung der Leistung

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

Die Sache ist es Art und Weise tooo lange dauert jedes Vorkommen von ersetzen & gt.

Haben Sie eine bessere Idee, um es schneller zu machen?

+0

Können Sie wie jede Rückmeldung auf Original-Code spped vs Jorge Code vs FastStrings bekommen? – gabr

+0

Das Problem mit StringReplace ist, wenn Sie viele Vorkommen haben, die ersetzt werden müssen. Für diesen Fall sollten Sie Ihre eigene Version schreiben, ähnlich der, die Gabr gepostet hat. Das Problem besteht darin, StringReplace nicht zweimal aufzurufen, sondern Dutzende von Ersatzoperationen zu verarbeiten. –

Antwort

7

Versuchen Sie FastStrings.pas von Peter Morris.

+0

FastStrings sind großartig, aber das Gerät funktioniert nicht mehr in Delphi 2009, was ein Problem sein könnte (wenn nicht jetzt, wenn (wenn) ein Upgrade durchgeführt wird). – gabr

+3

Faststrings springt schneller als die normale Delphi StringReplace-Funktion. Ich hoffe wirklich, dass Peter eine neue Version für Delphi 2009 veröffentlicht. –

+3

Seien Sie gewarnt, dass FastString nicht Unicode und die meisten XML ist. –

2

Das Problem ist, dass man die gesamte Zeichenfolge Größe zweimal iterieren (ein für den Ersatz & gt; von> und eine anderen & lt zu ersetzen, durch <).

Sie sollten iterieren mit einem für und einfach im Voraus überprüfen, wenn Sie eine & für ein GT finden; oder lt; und die sofortige ersetzen und dann überspringen 3 Zeichen ((g | l) t;). Auf diese Weise kann es in proportionaler Zeit zu der Größe der Zeichenfolge xml.Text.

Ein einfaches C# Beispiel, wie ich Delphi nicht kenne, aber tun sollte, um die allgemeine Idee zu bekommen.

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

Diese Ausgänge:

<xml>test</xml> 
+0

Das Problem besteht darin, die Zeichenfolge nicht zweimal zu durchlaufen, sondern viele Ersatzoperationen zu verarbeiten. Es gibt kein Problem, wenn es doppelt oder mehrmals aufgerufen wird, um verschiedene Zeichenfolgen zu ersetzen, wenn Sie es anders als in der RTL implementieren. –

2

Ungeprüfte Umwandlung des Codes C# Jorge Ferreira geschrieben.

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

Ist dies für Unicode sicher? –

+0

Nein, da String nicht Unicode, sondern Ansi ist. Es wäre, wenn Sie WideString anstelle von String verwenden. Und es wäre in Delphi 2009 oder Delphi für. Net, da beide standardmäßig Unicode-String verwenden. –

+0

Wer ist Jorge Ferreira? Ist es möglich, dass er sich jetzt in Smink umbenannt hat? –

2

Systools (Turbopower, jetzt Open Source) verfügt über eine ReplaceStringAllL-Funktion, die alle in einer Zeichenfolge ausführt.

8

Wenn Sie Delphi 2009 verwenden, ist diese Operation mit TStringBuilder etwa 3 mal schneller als mit ReplaceString. Es ist auch Unicode-sicher.

verwendete ich den Text von http://www.CodeGear.com mit allen Vorkommen von „<“ und „>“ geändert "&lt;" und "&gt;" als mein Ausgangspunkt.

Inklusive String Zuweisungen und die Erstellung/befreien Objekte, diese dauerte etwa 25 ms und 75 ms bzw. auf meinem System:

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

Sie sollten auf den Projektseiten Fastcode aussehen definitiv: http://fastcode.sourceforge.net/

Sie eine Herausforderung lief für eine schnellere StringReplace (Ansi StringReplace-Herausforderung), und der "Gewinner" war 14 mal schneller als die Delphi RTL.

Einige der Fastcode-Funktionen wurden in Delphi selbst in neueren Versionen (D2007, glaube ich) aufgenommen, so dass die Leistungsverbesserung je nach der von Ihnen verwendeten Delphi-Version stark variieren kann.

Wie bereits erwähnt, sollten Sie sich wirklich eine Unicode-basierte Lösung ansehen, wenn Sie ernsthaft XML verarbeiten möchten.

1

Wenn Sie mit mehrzeiligen Textdateien arbeiten, können Sie eine Leistung erzielen, indem Sie sie zeilenweise verarbeiten. In meinen Tests hat dieser Ansatz die Zeit in etwa 90% reduziert, um eine> 1MB xml-Datei zu ersetzen.

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; 

Hinweis: Delphi 10 Seattle.