function UTF8StringReplace_1(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string;
var
Matches: array of integer;
OldPat,Srch: string; // Srch and Oldp can contain uppercase versions of S,OldPattern
PatLength,P,Count, Capacity, i: Integer;
p1,p2, MemPos: pchar;
i1,i2, l: integer;
begin
if (Length(OldPattern)=0) or (Length(S)=0) then
exit(S);
if rfIgnoreCase in Flags then begin
Srch := UTF8LowerCase(S);
OldPat := UTF8LowerCase(OldPattern);
end else begin
Srch := S;
OldPat := OldPattern;
end;
{ Find matches }
Count := 0;
Capacity := 10;
SetLength(Matches, Capacity);
P:=PosEx(OldPat, Srch, 1);
if P=0 then exit(s);
if rfReplaceAll in Flags then { TODO : Consider using FindMatchesBoyerMooreCaseSensitive }
while p<>0 do begin
Matches[Count] := p;
inc(Count);
if Count=Capacity then begin { Grow }
inc(Capacity, 10);
SetLength(Matches, Capacity);
end;
P:=PosEx(OldPat,Srch,P+1);
end
else begin
Matches[Count] := p;
inc(Count);
end;
if rfIgnoreCase in Flags then begin { Correct match positions }
p1 := @Srch[1]; p2 := @S[1];
for i := 0 to Count-1 do begin
MemPos := @Srch[Matches[i]];
while p1<MemPos do begin
inc(p1, UTF8CharacterLengthFast(p1));
inc(p2, UTF8CharacterLengthFast(p2));
end;
Matches[i] := p2-@S[1]+1;
end;
end;
PatLength := Length(OldPat);
if Length(NewPattern)=PatLength then begin
//Result length will not change
Result:=S;
if (rfReplaceAll in Flags) then
for i := 0 to Count-1 do move(NewPattern[1], Result[Matches[i]], PatLength)
else
move(NewPattern[1], Result[Matches[0]], PatLength);
end else begin
SetLength(Result, Length(S) + Count*(Length(NewPattern)-Length(OldPattern)));
i1 := 1; i2 := 1;
for i := 0 to Count-1 do begin
l := Matches[i]-i1;
move(S[i1], Result[i2], l); { Copy text before pattern }
inc(i2, l); { Move to the location of the pattern }
i1 := Matches[i]+Length(OldPattern); { Move over the old pattern }
move(NewPattern[1], Result[i2], Length(NewPattern)); { Copy the new pattern }
inc(i2, Length(NewPattern));
end;
if i1<=Length(S) then
move(S[i1], Result[i2], Length(S)-i1+1); { Copy leftover text }
end;
end;