procedure SetUppercaseLookUp; var S : AnsiString; I : Integer; begin SetLength(S, 256); for I := 0 to 255 do PChar(Integer(S)+I)^ := Char(I); S := AnsiUpperCase(S); Move(S[1], UppercaseLookUp, 256); end; {SetUppercaseLookUp}
function AnsiUpperCase(const S : AnsiString) : AnsiString; var Len : Integer; PRes : PChar; begin {$IFDEF AllowLengthShortcut} Len := 0; if S <> '' then Len := PCardinal(Cardinal(S)-4)^; {$ELSE} Len := Length(S); {$ENDIF} SetLength(Result, Len); PRes := Pointer(Integer(Result)-1); while Len > 0 do begin PRes[Len] := UppercaseLookUp[S[Len]]; Dec(Len); end; end; {AnsiUpperCase}
procedure Move(const Source; var Dest; Count : Integer); var S, D : Cardinal; Temp, C, I : Integer; L : PInteger; begin S := Cardinal(@Source); D := Cardinal(@Dest); if S = D then Exit; if Count <= 4 then case Count of 1 : PByte(@Dest)^ := PByte(S)^; 2 : PWord(@Dest)^ := PWord(S)^; 3 : if D > S then begin PByte(Integer(@Dest)+2)^ := PByte(S+2)^; PWord(@Dest)^ := PWord(S)^; end else begin PWord(@Dest)^ := PWord(S)^; PByte(Integer(@Dest)+2)^ := PByte(S+2)^; end; 4 : PInteger(@Dest)^ := PInteger(S)^ else Exit; {Count <= 0} end else if D > S then begin Temp := PInteger(S)^; I := Integer(@Dest); C := Count - 4; L := PInteger(Integer(@Dest) + C); Inc(S, C); repeat L^ := PInteger(S)^; if Count <= 8 then Break; Dec(Count, 4); Dec(S, 4); Dec(L); until False; PInteger(I)^ := Temp; end else begin C := Count - 4; Temp := PInteger(S + Cardinal(C))^; I := Integer(@Dest) + C; L := @Dest; repeat L^ := PInteger(S)^; if Count <= 8 then Break; Dec(Count, 4); Inc(S, 4); Inc(L); until False; PInteger(I)^ := Temp; end; end; {Move}
function Pos(const SubStr : AnsiString; const Str : AnsiString) : Integer; var StrLen, SubLen, Remainder : Integer; PStr, PSub, PMax : PChar; FirstChar : Char; begin; Result := 0; {$IFDEF AllowLengthShortcut} if Str = '' then Exit; if SubStr = '' then Exit; StrLen := PCardinal(Cardinal(Str ) - 4)^; SubLen := PCardinal(Cardinal(SubStr) - 4)^; {$ELSE} SubLen := Length(SubStr); StrLen := Length(Str); {$ENDIF} if (SubLen = 0) then Exit; if (SubLen > StrLen) then Exit; PSub := Pointer(SubStr); PStr := Pointer(Str); {Search Start Position} PMax := PStr + StrLen - SubLen; {Maximum Start Position} FirstChar := PSub^; if SubLen = 1 then repeat {Single Character Saarch} if PStr^ = FirstChar then begin Result := PStr + 1 - Pointer(Str); Exit; end; if PStr[1] = FirstChar then begin if PStr < PMax then Result := PStr + 2 - Pointer(Str); Exit; end; Inc(PStr, 2); until PStr > PMax else begin {Multi-Character Search} Dec(SubLen, 2); {Characters to Check after Match} repeat if PStr^ = FirstChar then begin Remainder := SubLen; while True do begin if (PSub[Remainder ] <> PStr[Remainder ]) or (PSub[Remainder+1] <> PStr[Remainder+1]) then Break; {No Match} Dec(Remainder, 2); if Remainder < 0 then begin Result := PStr + 1 - Pointer(Str); Exit; end; end; end; if PStr[1] = FirstChar then begin Remainder := SubLen; while True do begin if (PSub[Remainder ] <> PStr[Remainder+1]) or (PSub[Remainder+1] <> PStr[Remainder+2]) then Break; {No Match} Dec(Remainder, 2); if Remainder < 0 then begin if PStr < PMax then Result := PStr + 2 - Pointer(Str); Exit; end; end; end; Inc(PStr, 2); until PStr > PMax; end; end; {Pos}
function PosEx(const SubStr : AnsiString; const Str : AnsiString; const StartPos : Cardinal) : Integer; var StrLen, SubLen, Remainder : Integer; PStr, PSub, PMax : PChar; FirstChar : Char; {First Character of SubStr} begin; Result := 0; {$IFDEF AllowLengthShortcut} if Str = '' then Exit; if SubStr = '' then Exit; StrLen := PCardinal(Cardinal(Str ) - 4)^; SubLen := PCardinal(Cardinal(SubStr) - 4)^; {$ELSE} SubLen := Length(SubStr); StrLen := Length(Str); {$ENDIF} if (SubLen = 0) then Exit; PSub := Pointer(SubStr); PStr := Pointer(Str); PMax := PStr + StrLen - SubLen; {Maximum Start Position} {The following 3 Lines are the only Difference between Pos and PosEx} Inc(PStr, StartPos - 1); if PStr > PMax then Exit; FirstChar := PSub^; if SubLen = 1 then repeat {Single Character Saarch} if PStr^ = FirstChar then begin Result := PStr + 1 - Pointer(Str); Exit; end; if PStr[1] = FirstChar then begin if PStr < PMax then {Within Valid Range} Result := PStr + 2 - Pointer(Str); Exit; end; Inc(PStr, 2); until PStr > PMax else begin {Multi-Character Search} Dec(SubLen, 2); {Characters to Check after Match} repeat if PStr^ = FirstChar then begin Remainder := SubLen; while True do begin if (PSub[Remainder ] <> PStr[Remainder ]) or (PSub[Remainder+1] <> PStr[Remainder+1]) then Break; {No Match} Dec(Remainder, 2); if Remainder < 0 then begin {First Char already Checked} Result := PStr + 1 - Pointer(Str); Exit; end; end; end; if PStr[1] = FirstChar then begin Remainder := SubLen; while True do begin if (PSub[Remainder ] <> PStr[Remainder+1]) or (PSub[Remainder+1] <> PStr[Remainder+2]) then Break; {No Match} Dec(Remainder, 2); if Remainder < 0 then begin {First Char already Checked} if PStr < PMax then {Within Valid Range} Result := PStr + 2 - Pointer(Str); Exit; end; end; end; Inc(PStr, 2); until PStr > PMax; end; end; {PosEx}
{Replace All Occurances - Ignoring Case} function AnsiStringReplaceAllIC(const Src, Old, New : AnsiString) : AnsiString; var SourceString, SearchString : AnsiString; SrcLen, OldLen, NewLen, Found, Start, ResultLen, Count : Cardinal; PSrc, PNew, PRes : PChar; LengthCanGrow : Boolean; begin {$IFDEF AllowLengthShortcut} SrcLen := 0; if (Src <> '') then SrcLen := PCardinal(Cardinal(Src)-4)^; OldLen := 0; if (Old <> '') then OldLen := PCardinal(Cardinal(Old)-4)^; {$ELSE} SrcLen := Length(Src); OldLen := Length(Old); {$ENDIF} if (OldLen = 0) or (SrcLen < OldLen) then begin if SrcLen = 0 then Result := '' {Needed for Non-Nil Zero Length Strings} else Result := Src end else begin SourceString := AnsiUpperCase(Src); SearchString := AnsiUpperCase(Old); Found := Pos(SearchString, SourceString); if Found <> 0 then begin {First Match Found} {$IFDEF AllowLengthShortcut} NewLen := 0; if (New <> '') then NewLen := PCardinal(Cardinal(New)-4)^; {$ELSE} NewLen := Length(New); {$ENDIF} LengthCanGrow := False; if NewLen > OldLen then begin {Set Initial Result Length - May be Adjusted Later} if (SrcLen > 8*1024) {Skip DIV and 64-Bit Math if Possible} and (Int64(NewLen div OldLen) * Int64(SrcLen) > 64*1024*1024) then begin {Large - Initally Allocate Space for First Replace Only} ResultLen := SrcLen - OldLen + NewLen; if ResultLen > MaxStrLen then Error(reOutOfMemory); LengthCanGrow := True; end else begin {Allocate Enough Space for Maximum Possible Replacements} ResultLen := SrcLen + (((SrcLen - Found + 1) div OldLen) * (NewLen - OldLen)); end; end else ResultLen := SrcLen; {Final Result Length will be <= Src Length} SetLength(Result, ResultLen); PNew := Pointer(New); PSrc := Pointer(Src); PRes := Pointer(Result); Start := 1; repeat if Found <> Start then begin Count := Found - Start; Move(PSrc^, PRes^, Count); Inc(PSrc, Count); Inc(PRes, Count); end; if NewLen = 1 then PRes^ := PNew^ {Optimize Single Byte Move} else Move(PNew^, PRes^, NewLen); Inc(PRes, NewLen); Inc(PSrc, OldLen); Start := Found + OldLen; if Start > SrcLen then Break; Found := PosEx(SearchString, SourceString, Start); if Found <> 0 then if LengthCanGrow then begin {Grow Result Length} Inc(ResultLen, NewLen - OldLen); if ResultLen > MaxStrLen then Error(reOutOfMemory); SetLength(Result, ResultLen); PRes := Pointer(Result); end; until Found = 0; Count := SrcLen - Start + 1; Move(PSrc^, PRes^, Count); Inc(Count, Cardinal(PRes) - Cardinal(Result)); if Count <> ResultLen then SetLength(Result, Count); {Correct Result Length if Necessary} end else {No Matches Found} Result := Src end; end; {AnsiStringReplaceAllIC}
{Replace All Occurances - Case Sensitive} function AnsiStringReplaceAllCS(const Src, Old, New : AnsiString) : AnsiString; var SrcLen, OldLen, NewLen, Found, Start, ResultLen, Count : Cardinal; PSrc, PNew, PRes : PChar; LengthCanGrow : Boolean; begin {$IFDEF AllowLengthShortcut} SrcLen := 0; if (Src <> '') then SrcLen := PCardinal(Cardinal(Src)-4)^; OldLen := 0; if (Old <> '') then OldLen := PCardinal(Cardinal(Old)-4)^; {$ELSE} SrcLen := Length(Src); OldLen := Length(Old); {$ENDIF} if (OldLen = 0) or (SrcLen < OldLen) then begin if SrcLen = 0 then Result := '' {Needed for Non-Nil Zero Length Strings} else Result := Src end else begin Found := Pos(Old, Src); if Found <> 0 then begin {First Match Found} {$IFDEF AllowLengthShortcut} NewLen := 0; if (New <> '') then NewLen := PCardinal(Cardinal(New)-4)^; {$ELSE} NewLen := Length(New); {$ENDIF} LengthCanGrow := False; if NewLen > OldLen then begin {Set Initial Result Length - May be Adjusted Later} if (SrcLen > 8*1024) {Skip DIV and 64-Bit Math if Possible} and (Int64(NewLen div OldLen) * Int64(SrcLen) > 64*1024*1024) then begin {Large - Initally Allocate Space for First Replace Only} ResultLen := SrcLen - OldLen + NewLen; if ResultLen > MaxStrLen then Error(reOutOfMemory); LengthCanGrow := True; end else begin {Allocate Enough Space for Maximum Possible Replacements} ResultLen := SrcLen + (((SrcLen - Found + 1) div OldLen) * (NewLen - OldLen)); end; end else ResultLen := SrcLen; {Final Result Length will be <= Src Length} SetLength(Result, ResultLen); PNew := Pointer(New); PSrc := Pointer(Src); PRes := Pointer(Result); Start := 1; repeat if Found <> Start then begin Count := Found - Start; Move(PSrc^, PRes^, Count); Inc(PSrc, Count); Inc(PRes, Count); end; if NewLen = 1 then PRes^ := PNew^ {Optimize Single Byte Move} else Move(PNew^, PRes^, NewLen); Inc(PRes, NewLen); Inc(PSrc, OldLen); Start := Found + OldLen; if Start > SrcLen then Break; Found := PosEx(Old, Src, Start); if Found <> 0 then if LengthCanGrow then begin {Grow Result Length} Inc(ResultLen, NewLen - OldLen); if ResultLen > MaxStrLen then Error(reOutOfMemory); SetLength(Result, ResultLen); PRes := Pointer(Result); end; until Found = 0; Count := SrcLen - Start + 1; Move(PSrc^, PRes^, Count); Inc(Count, Cardinal(PRes) - Cardinal(Result)); if Count <> ResultLen then SetLength(Result, Count); {Correct Result Length if Necessary} end else {No Matches Found} Result := Src end; end; {AnsiStringReplaceAllCS}
{Replace First Occurance Only - Ignoring Case} function AnsiStringReplace1stIC(const Src, Old, New : AnsiString) : AnsiString; var SourceString, SearchString : AnsiString; SrcLen, OldLen, NewLen, Found, ResultLen : Cardinal; PSrc, PNew, PRes : PChar; begin {$IFDEF AllowLengthShortcut} SrcLen := 0; if (Src <> '') then SrcLen := PCardinal(Cardinal(Src)-4)^; OldLen := 0; if (Old <> '') then OldLen := PCardinal(Cardinal(Old)-4)^; {$ELSE} SrcLen := Length(Src); OldLen := Length(Old); {$ENDIF} if (OldLen = 0) or (SrcLen < OldLen) then begin if SrcLen = 0 then Result := '' {Needed for Non-Nil Zero Length Strings} else Result := Src end else begin SourceString := AnsiUpperCase(Src); SearchString := AnsiUpperCase(Old); Found := Pos(SearchString, SourceString); if Found <> 0 then begin {Match Found} {$IFDEF AllowLengthShortcut} NewLen := 0; if (New <> '') then NewLen := PCardinal(Cardinal(New)-4)^; {$ELSE} NewLen := Length(New); {$ENDIF} ResultLen := SrcLen - OldLen + NewLen; if ResultLen > MaxStrLen then Error(reOutOfMemory); SetLength(Result, ResultLen); Dec(Found); PNew := Pointer(New); PSrc := Pointer(Src); PRes := Pointer(Result); if NewLen = OldLen then begin Move(PSrc^, PRes^, SrcLen); Inc(PRes, Found); Move(PNew^, PRes^, NewLen); end else begin Move(PSrc^, PRes^, Found); Inc(PRes, Found); Inc(PSrc, Found + OldLen); if NewLen <> 0 then begin Move(PNew^, PRes^, NewLen); Inc(PRes, NewLen); end; Move(PSrc^, PRes^, SrcLen - Found - OldLen); end; end else {No Matches Found} Result := Src end; end; {AnsiStringReplace1stIC}
{Replace First Occurance Only - Case Sensitive} function AnsiStringReplace1stCS(const Src, Old, New : AnsiString) : AnsiString; var SrcLen, OldLen, NewLen, Found, ResultLen : Cardinal; PSrc, PNew, PRes : PChar; begin {$IFDEF AllowLengthShortcut} SrcLen := 0; if (Src <> '') then SrcLen := PCardinal(Cardinal(Src)-4)^; OldLen := 0; if (Old <> '') then OldLen := PCardinal(Cardinal(Old)-4)^; {$ELSE} SrcLen := Length(Src); OldLen := Length(Old); {$ENDIF} if (OldLen = 0) or (SrcLen < OldLen) then begin if SrcLen = 0 then Result := '' {Needed for Non-Nil Zero Length Strings} else Result := Src end else begin Found := Pos(Old, Src); if Found <> 0 then begin {Match Found} {$IFDEF AllowLengthShortcut} NewLen := 0; if (New <> '') then NewLen := PCardinal(Cardinal(New)-4)^; {$ELSE} NewLen := Length(New); {$ENDIF} ResultLen := SrcLen - OldLen + NewLen; if ResultLen > MaxStrLen then Error(reOutOfMemory); SetLength(Result, ResultLen); Dec(Found); PNew := Pointer(New); PSrc := Pointer(Src); PRes := Pointer(Result); if NewLen = OldLen then begin Move(PSrc^, PRes^, SrcLen); Inc(PRes, Found); Move(PNew^, PRes^, NewLen); end else begin Move(PSrc^, PRes^, Found); Inc(PRes, Found); Inc(PSrc, Found + OldLen); if NewLen <> 0 then begin Move(PNew^, PRes^, NewLen); Inc(PRes, NewLen); end; Move(PSrc^, PRes^, SrcLen - Found - OldLen); end; end else {No Matches Found} Result := Src end; end; {AnsiStringReplace1stCS}
//Author: John O'Harrow //Optimized for: All //Instructionset(s): IA32 //Original Name: AnsiStringReplaceJOH_PAS
function AnsiStringReplaceFastcodePascal(const S, OldPattern, NewPattern: AnsiString; Flags: TReplaceFlags): AnsiString; type TReplaceFunction = function(const Src, Old, New : AnsiString) : AnsiString; const StringReplaceFunction : array[0..3] of TReplaceFunction = (AnsiStringReplace1stCS, AnsiStringReplaceAllCS, AnsiStringReplace1stIC, AnsiStringReplaceAllIC); begin Result := StringReplaceFunction[PByte(@Flags)^](S, OldPattern, NewPattern); end;