delphi - una - String Reemplazar alternativas para mejorar el rendimiento
replace c# varios caracteres (7)
Conversión no probada del código C # escrito por 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;
Estoy usando StringReplace para reemplazar & gt y & lt por el mismo char en un XML generado como este:
StringReplace(xml.Text,''>'',''>'',[rfReplaceAll]) ;
StringReplace(xml.Text,''<'',''<'',[rfReplaceAll]) ;
La cosa es que toma demasiado tiempo reemplazar cada ocurrencia de & gt.
¿Haces alguna idea mejor para hacerlo más rápido?
Pruebe FastStrings.pas de Peter Morris.
Systools (Turbopower, ahora de código abierto) tiene una función ReplaceStringAllL que los hace todos en una cadena.
Definitivamente debe mirar las páginas del proyecto de Fastcode: http://fastcode.sourceforge.net/
Ejecutó un desafío para un StringReplace más rápido (desafío Ansi StringReplace), y el ''ganador'' fue 14 veces más rápido que Delphi RTL.
Varias de las funciones de código rápido se han incluido dentro de Delphi en versiones recientes (creo que en D2007), por lo que la mejora del rendimiento puede variar drásticamente dependiendo de la versión de Delphi que esté utilizando.
Como se mencionó anteriormente, realmente debería considerar una solución basada en Unicode si realmente quiere procesar XML.
El problema es que está iterando el tamaño completo de la cadena dos veces (una para reemplazar & gt; por> y otra para reemplazar & lt; por <).
Debe repetir con un y simplemente comprobar siempre que encuentre un & para un gt; o lt; y hacer el reemplazo inmediato y luego omitir 3 caracteres ((g | l) t;). De esta forma puede hacerlo en un tiempo proporcional al tamaño de la cadena xml.Text .
Un simple ejemplo de C # ya que no conozco Delphi, pero debería hacerlo para que usted tenga una idea general.
String s = "<xml>test</xml>";
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));
Esto produce:
<xml>test</xml>
Si está utilizando Delphi 2009, esta operación es aproximadamente 3 veces más rápida con TStringBuilder que con ReplaceString. También es seguro para Unicode.
Utilicé el texto de http://www.CodeGear.com con todas las ocurrencias de "<" y ">" cambiadas a "<"
y ">"
como mi punto de partida
Incluyendo asignaciones de cadenas y creando / liberando objetos, estos tardaron unos 25 ms y 75 ms respectivamente en mi sistema:
function TForm1.TestStringBuilder(const aString: string): string;
var
sb: TStringBuilder;
begin
StartTimer;
sb := TStringBuilder.Create;
sb.Append(aString);
sb.Replace(''>'', ''>'');
sb.Replace(''<'', ''<'');
Result := sb.ToString();
FreeAndNil(sb);
StopTimer;
end;
function TForm1.TestStringReplace(const aString: string): string;
begin
StartTimer;
Result := StringReplace(aString,''>'',''>'',[rfReplaceAll]) ;
Result := StringReplace(Result,''<'',''<'',[rfReplaceAll]) ;
StopTimer;
end;
Cuando se trata de archivos de texto de líneas múltiples, puede obtener algún rendimiento procesándolo línea por línea. En mis pruebas, este enfoque redujo el tiempo en aproximadamente 90% para el proceso reemplaza en> 1MB archivo 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, ''>'', ''>'', [rfReplaceAll]);
line := StringReplace(line, ''<'', ''<'', [rfReplaceAll]);
xml[i] := line;
end;
end;
Nota: Delphi 10 Seattle.