Browse Source

* Faster stringreplace (bug ID 26864)

git-svn-id: trunk@33055 -
michael 9 years ago
parent
commit
cf530f117e

+ 80 - 0
rtl/objpas/sysutils/syssr.inc

@@ -1,3 +1,82 @@
+var
+  OldPat,Srch: string; // Srch and Oldp can contain uppercase versions of S,OldPattern
+  PatLength,NewPatLength,P,Cnt,PatCount,PrevP: Integer;
+  c,d: SRPChar ;
+  
+begin
+  PatLength:=Length(OldPattern);
+  if PatLength=0 then begin
+    Result:=S;
+    exit;
+  end;
+
+  if rfIgnoreCase in Flags then begin
+    Srch:=SRUpperCase(S);
+    OldPat:=SRUpperCase(OldPattern);
+  end else begin
+    Srch:=S;
+    OldPat:=OldPattern;
+  end;
+
+  PatLength:=Length(OldPat);
+  if Length(NewPattern)=PatLength then begin
+    //Result length will not change
+    Result:=S;
+    P:=1;
+    repeat
+      P:=Pos(OldPat,Srch,P);
+      if P>0 then begin
+        move(NewPattern[1],Result[P],PatLength);
+        if not (rfReplaceAll in Flags) then exit;
+        inc(P,PatLength);
+      end;
+    until p=0;
+  end else begin
+    //Different pattern length -> Result length will change
+    //To avoid creating a lot of temporary strings, we count how many
+    //replacements we're going to make.
+    P:=1; PatCount:=0;
+    repeat
+      P:=Pos(OldPat,Srch,P);
+      if P>0 then begin
+        inc(P,PatLength);
+        inc(PatCount);
+        if not (rfReplaceAll in Flags) then break;
+      end;
+    until p=0;
+    if PatCount=0 then begin
+      Result:=S;
+      exit;
+    end;
+    NewPatLength:=Length(NewPattern);
+    SetLength(Result,Length(S)+PatCount*(NewPatLength-PatLength)*SizeOf(SRChar));
+    P:=1; PrevP:=0;
+    c:=SRPChar(Result); d:=SRPChar(S);
+    repeat
+      P:=Pos(OldPat,Srch,P);
+      if P>0 then begin
+        Cnt:=P-PrevP-1;
+        if Cnt>0 then begin
+          Move(d^,c^,Cnt);
+          inc(c,Cnt);
+          inc(d,Cnt);
+        end;
+        if NewPatLength>0 then begin
+          Move(NewPattern[1],c^,NewPatLength);
+          inc(c,NewPatLength);
+        end;
+        inc(P,PatLength);
+        inc(d,PatLength);
+        PrevP:=P-1;
+        if not (rfReplaceAll in Flags) then break;
+      end;
+    until p=0;
+    Cnt:=Length(S)-PrevP;
+    if Cnt>0 then Move(d^,c^,Cnt);
+  end;
+end;
+
+(*
 var
   Srch,OldP,RemS: SRString; // Srch and Oldp can contain uppercase versions of S,OldPattern
   P : Integer;
@@ -34,3 +113,4 @@ begin
       end;
     end;
 end;
+*)

+ 4 - 0
rtl/objpas/sysutils/sysstr.inc

@@ -2628,6 +2628,8 @@ end;
 {$define INSTRINGREPLACE}
 {$define SRString:=String}
 {$define SRUpperCase:=AnsiUppercase}
+{$define SRPCHAR:=PChar}
+{$define SRCHAR:=Char}
 
 Function StringReplace(const S, OldPattern, NewPattern: string;  Flags: TReplaceFlags): string;
 {$i syssr.inc}
@@ -2635,6 +2637,8 @@ Function StringReplace(const S, OldPattern, NewPattern: string;  Flags: TReplace
 {$undef INSTRINGREPLACE}
 {$undef SRString}
 {$undef SRUpperCase}
+{$undef SRPCHAR}
+{$undef SRCHAR}
 
 Function IsDelimiter(const Delimiters, S: string; Index: Integer): Boolean;
 

+ 5 - 0
rtl/objpas/sysutils/sysuni.inc

@@ -537,9 +537,14 @@ end;
 {$define INUNICODESTRINGREPLACE}
 {$define SRString:=UnicodeString}
 {$define SRUpperCase:=WideUppercase}
+{$define SRPCHAR:=PChar}
+{$define SRCHAR:=Char}
+
 function UnicodeStringReplace(const S, OldPattern, NewPattern: UnicodeString;  Flags: TReplaceFlags): UnicodeString;
 {$i syssr.inc}
 
 {$undef INUNICODESTRINGREPLACE}
 {$undef SRString}
 {$undef SRUpperCase}
+{$undef SRPCHAR}
+{$undef SRCHAR}

+ 5 - 0
rtl/objpas/sysutils/syswide.inc

@@ -184,9 +184,14 @@ end;
 {$define INWIDESTRINGREPLACE}
 {$define SRString:=WideString}
 {$define SRUpperCase:=WideUppercase}
+{$define SRPChar:=PWideChar}
+{$define SRChar:=WideChar}
+
 function WideStringReplace(const S, OldPattern, NewPattern: WideString;  Flags: TReplaceFlags): WideString;
 {$i syssr.inc}
 
 {$undef INWIDESTRINGREPLACE}
 {$undef SRString}
 {$undef SRUpperCase}
+{$undef SRPChar}
+{$undef SRChar}