StringReplace alternatives to improve performance

前端 未结 8 752
温柔的废话
温柔的废话 2021-02-04 12:46

I am using StringReplace to replace > and < by the char itself in a generated XML like this:

StringReplace(xml.Text,\'>\',\'>\',[rfReplaceA         


        
相关标签:
8条回答
  • 2021-02-04 13:07

    Systools (Turbopower, now open source) has a ReplaceStringAllL function that does all of them in a string.

    0 讨论(0)
  • 2021-02-04 13:12

    Try FastStrings.pas from Peter Morris.

    0 讨论(0)
  • 2021-02-04 13:12

    Untested conversion of the C# code written by Jorge Ferreira.

    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 讨论(0)
  • 2021-02-04 13:13

    The problem is that you are iterating the entire string size twice (one for replacing &gt; by > and another one to replace &lt; by <).

    You should iterate with a for and simply check ahead whenever you find a & for a gt; or lt; and do the immediate replace and then skipping 3 characters ((g|l)t;). This way it can do that in proportional time to the size of the string xml.Text.


    A simple C# example as I do not know Delphi but should do for you to get the general idea.

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

    This outputs:

    <xml>test</xml>
    
    0 讨论(0)
  • 2021-02-04 13:30

    You should definitely look at the Fastcode project pages: http://fastcode.sourceforge.net/

    They ran a challenge for a faster StringReplace (Ansi StringReplace challenge), and the 'winner' was 14 times faster than the Delphi RTL.

    Several of the fastcode functions have been included within Delphi itself in recent versions (D2007 on, I think), so the performance improvement may vary dramatically depending on which Delphi version you are using.

    As mentioned before, you should really be looking at a Unicode-based solution if you're serious about processing XML.

    0 讨论(0)
  • 2021-02-04 13:30

    When you are dealing with a multiline text files, you can get some performance by processing it line by line. This approach reduced time in about 90% to replaces on >1MB xml file.

    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;
    
    0 讨论(0)
提交回复
热议问题