function SanitizeXML_Original(
const AValue:
String):
String;
var
i: Integer;
LChr: Char;
LStrBldr: TStringBuilder;
begin
LStrBldr := TStringBuilder.Create;
try
for i := 1
to Length(AValue)
do
begin
LChr := AValue[i];
if (LChr = #9)
or (LChr = #10)
or (LChr = #13)
or
((LChr >= #32)
and (LChr <= #$D7FF))
or
((LChr >= #$E000)
and (LChr <= #$FFFD))
then
LStrBldr.Append(LChr);
end;
Result := LStrBldr.ToString;
finally
LStrBldr.Free;
end;
end;
function SanitizeXML_PChar(
const AValue:
String):
String;
var
Src, SrcEnd: PChar;
LStrBldr: TStringBuilder;
C: Char;
begin
LStrBldr := TStringBuilder.Create(Length(AValue));
try
Src := PChar(AValue);
SrcEnd := Src + Length(AValue);
while Src < SrcEnd
do
begin
C := Src^;
if (C = #9)
or (C = #10)
or (C = #13)
or
((C >= #32)
and (C <= #$D7FF))
or
((C >= #$E000)
and (C <= #$FFFD))
then
LStrBldr.Append(C);
Inc(Src);
end;
Result := LStrBldr.ToString;
finally
LStrBldr.Free;
end;
end;
function SanitizeXML_Direct(
const AValue:
String):
String;
var
Src: PChar;
Dest: PChar;
Len, i: Integer;
C: Char;
begin
Len := Length(AValue);
SetLength(Result, Len);
Src := PChar(AValue);
Dest := PChar(Result);
for i := 0
to Len - 1
do
begin
C := Src[i];
if (C = #9)
or (C = #10)
or (C = #13)
or
((C >= #32)
and (C <= #$D7FF))
or
((C >= #$E000)
and (C <= #$FFFD))
then
begin
Dest^ := C;
Inc(Dest);
end;
end;
SetLength(Result, Dest - PChar(Result));
end;
function SanitizeXML_Direct_2(
const AValue:
String):
String;
var
Src: PChar;
Dest: PChar;
Len, i: Integer;
C: Char;
begin
Len := Length(AValue);
SetLength(Result, Len);
Src := PChar(AValue);
Dest := PChar(Result);
for i := 0
to Len - 1
do
begin
C := Src[i];
case C
of
#9, #10, #13, #32..#$D7FF, #$E000..#$FFFD:
begin
Dest^ := C;
Inc(Dest);
end;
end;
end;
SetLength(Result, Dest - PChar(Result));
end;
function SanitizeXML_Direct_3(
const AValue:
String):
String;
var
Src, SrcEnd, Dest: PChar;
Len: Integer;
begin
Len := Length(AValue);
SetLength(Result, Len);
Src := PChar(AValue);
Dest := PChar(Result);
SrcEnd := Src + Len;
while Src < SrcEnd
do
begin
case Src^
of
#9, #10, #13,
#32..#$D7FF,
#$E000..#$FFFD:
begin
Dest^ := Src^;
Inc(Dest);
end;
end;
Inc(Src);
end;
SetLength(Result, Dest - PChar(Result));
end;
procedure RunBenchmark;
const
Iterations = 1000;
var
i: Integer;
InputStr, ResultStr1, ResultStr2, ResultStr3, ResultStr4, ResultStr5:
String;
SW: TStopwatch;
begin
// Beispiel-XML mit gültigen/ungültigen Zeichen
InputStr := StringOfChar('
A', 10000) + #0 + #1 + #2 + #3 + #4 + #5 + #6 + #7 +#8 + #$FFFF + StringOfChar('
B', 10000);
// Original
SW := TStopwatch.StartNew;
for i := 1
to Iterations
do
ResultStr1 := SanitizeXML_Original(InputStr);
SW.Stop;
OutputDebugString(PChar('
Original TStringBuilder: ' + SW.Elapsed.TotalMilliseconds.ToString + '
ms'));
// PChar + TStringBuilder
SW := TStopwatch.StartNew;
for i := 1
to Iterations
do
ResultStr2 := SanitizeXML_PChar(InputStr);
SW.Stop;
OutputDebugString(PChar('
Optimiert mit PChar: ' + SW.Elapsed.TotalMilliseconds.ToString + '
ms'));
// Direkte Speicherzugriffe
SW := TStopwatch.StartNew;
for i := 1
to Iterations
do
ResultStr3 := SanitizeXML_Direct(InputStr);
SW.Stop;
OutputDebugString(PChar('
Direkter Zugriff: ' + SW.Elapsed.TotalMilliseconds.ToString + '
ms'));
// Direkte Speicherzugriffe mit case-of
SW := TStopwatch.StartNew;
for i := 1
to Iterations
do
ResultStr4 := SanitizeXML_Direct_2(InputStr);
SW.Stop;
OutputDebugString(PChar('
Direkter Zugriff 2: ' + SW.Elapsed.TotalMilliseconds.ToString + '
ms'));
// Direkte Speicherzugriffe mit while statt for und mit case-of
SW := TStopwatch.StartNew;
for i := 1
to Iterations
do
ResultStr5 := SanitizeXML_Direct_3(InputStr);
SW.Stop;
OutputDebugString(PChar('
Direkter Zugriff 3: ' + SW.Elapsed.TotalMilliseconds.ToString + '
ms'));
end;