Registriert seit: 18. Mär 2005
1.682 Beiträge
Delphi 2006 Enterprise
|
Re: Mehrfaches suchen und ersetzten in einem Druchlauf
22. Apr 2006, 19:34
Hallo,
ich hab' mal meine Routine etwas überarbeitet. Jetzt kann man einstellen, ob Groß-/Kleinschreibung beachtet werden soll.
Delphi-Quellcode:
function StringReplaceMultiple(const Source: AnsiString;
const OldPatterns, NewPatterns: array of AnsiString;
CaseSensitive: Boolean = True): AnsiString;
// Replace every occurrence
type
TFoundPos = record
Position: Integer;
PatternNum: Integer;
end;
var
C: Integer;
FoundCount: Integer;
SourcePosition: Integer;
PatternCount: Integer;
Positions: array of TFoundPos;
PositionLength: Integer;
PatternNum: Integer;
SourceLength, OldPatternLength, NewPatternLength: Integer;
OldLengths, NewLengths: array of Integer;
DeltaOld: Integer;
Delta: Integer;
PSource, PDest, PNew: PAnsiChar;
SearchSource: AnsiString;
CasePatterns: array of AnsiString;
I: Integer;
begin
if (Source = '') or (Length(OldPatterns) <> Length(NewPatterns)) then
begin
Result := Source;
Exit;
end;
try
// Initialize some variables
PatternCount := Length(OldPatterns);
SourceLength := Length(Source);
SetLength(OldLengths, PatternCount);
SetLength(NewLengths, PatternCount);
Delta := 0;
DeltaOld := 0;
for C := 0 to PatternCount - 1 do
begin
OldLengths[C] := Length(OldPatterns[C]);
NewLengths[C] := Length(NewPatterns[C]);
Inc(DeltaOld, OldLengths[C]);
end;
DeltaOld := Round(DeltaOld / PatternCount);
SetLength(CasePatterns, PatternCount);
if CaseSensitive then
begin
SearchSource := Source;
for C := 0 to PatternCount - 1 do
CasePatterns[C] := OldPatterns[C];
end else
begin
SearchSource := AnsiLowerCase(Source);
for C := 0 to PatternCount - 1 do
CasePatterns[C] := AnsiLowerCase(OldPatterns[C]);
end;
FoundCount := 0;
// ----------------------------------
// Check the amount of replaces
// ----------------------------------
// We *should* range check here, but who has strings > 2GB ?
PositionLength := SourceLength div DeltaOld + 1;
SetLength(Positions, PositionLength);
C := 1;
while C <= SourceLength do
begin
for PatternNum := 0 to PatternCount - 1 do
begin
if (SearchSource[C]) = (CasePatterns[PatternNum][1]) then // Check first char before we waste a jump to CompareMem
begin
if CompareMem(@SearchSource[C], @CasePatterns[PatternNum][1], OldLengths[PatternNum]) then
begin
if FoundCount >= PositionLength then
begin
Inc(PositionLength, 4);
SetLength(Positions, PositionLength);
end;
Positions[FoundCount].Position := C; // Store the found position
Positions[FoundCount].PatternNum := PatternNum;
Inc(FoundCount);
Inc(C, OldLengths[PatternNum] - 1); // Jump to after OldPattern
Inc(Delta, NewLengths[PatternNum] - OldLengths[PatternNum]);
Break;
end;
end;
end;
Inc(C);
end;
SetLength(CasePatterns, 0);
// ----------------------------------
// Actual replace
// ----------------------------------
if FoundCount > 0 then // Have we found anything?
begin
// We know the length of the result
// Again, we *should* range check here...
SetLength(Result, SourceLength + Delta);
// Initialize some variables
SourcePosition := 1;
PSource := PAnsiChar(Source);
PDest := PAnsiChar(Result);
// Replace...
for C := 0 to FoundCount - 1 do
begin
// Copy original and advance resultpos
PNew := PAnsiChar(NewPatterns[Positions[C].PatternNum]);
Move(PSource^, PDest^, Positions[C].Position - SourcePosition);
Inc(PDest, Positions[C].Position - SourcePosition);
// Append NewPattern and advance resultpos
Move(PNew^, PDest^, NewLengths[Positions[C].PatternNum]);
Inc(PDest, NewLengths[Positions[C].PatternNum]);
// Jump to after OldPattern
Inc(PSource, Positions[C].Position - SourcePosition + OldLengths[Positions[C].PatternNum]);
SourcePosition := Positions[C].Position + OldLengths[Positions[C].PatternNum];
end;
// Append characters after last OldPattern
Move(PSource^, PDest^, SourceLength - SourcePosition + 1);
end else
Result := Source; // Nothing to replace
// Clean up
Finalize(Positions);
except
end;
end;
Die Routine benötigt jeztt die Unit SysUtils.
Gruß
xaromz
|
|
Zitat
|