📄 faststrings.pas
字号:
mov ESI, EAX
mov EDI, EDX
//The following loop is the same as repNZ MovSB, but oddly quicker !
@Loop:
//Get the source byte
Mov AL, [ESI]
//Point to next byte
Inc ESI
//Put it into the Dest
mov [EDI], AL
//Point dest to next position
Inc EDI
//Dec ECX to note how many we have left to copy
Dec ECX
//If ECX <> 0 then loop
Jnz @Loop
//Another optimization note.
//Many people like to do this
//Mov AL, [ESI]
//Mov [EDI], Al
//Inc ESI
//Inc ESI
//There is a hidden problem here, I wont go into too much detail, but
//the pentium can continue processing instructions while it is still
//working out the result of INC ESI or INC EDI
//(almost like a multithreaded CPU)
//if, however, you go to use them while they are still being calculated
//the processor will stop until they are calculated (a penalty)
//Therefore I alter ESI and EDI as far in advance as possible of using them
//Pop the critical Delphi registers that we have altered
pop EDI
pop ESI
@JustQuit:
end;
function FastAnsiReplace(const S, OldPattern, NewPattern: string;
Flags: TReplaceFlags): string;
var
BufferSize, BytesWritten: Integer;
SourceString, FindString: string;
ResultPChar : PChar;
FindPChar, ReplacePChar: PChar;
SPChar, SourceStringPChar, PrevSourceStringPChar: PChar;
FinalSourceMarker : PChar;
SourceLength, FindLength, ReplaceLength, CopySize: Integer;
FinalSourcePosition: Integer;
begin
//Set up string lengths
BytesWritten := 0;
SourceLength := Length(S);
FindLength := Length(OldPattern);
ReplaceLength := Length(NewPattern);
//Quick exit
if (SourceLength = 0) or (FindLength = 0) or
(FindLength > SourceLength) then
begin
Result := S;
Exit;
end;
//Set up the source string and find string
if rfIgnoreCase in Flags then
begin
SourceString := AnsiUpperCase(S);
FindString := AnsiUpperCase(OldPattern);
end
else
begin
SourceString := S;
FindString := OldPattern;
end;
//Set up the result buffer size and pointers
try
if ReplaceLength <= FindLength then
//Result cannot be larger, only same size or smaller
BufferSize := SourceLength
else
//Assume a source string made entired of the sub string
BufferSize := (SourceLength * ReplaceLength) div
FindLength;
//10 times is okay for starters. We don't want to
//go allocating much more than we need.
if BufferSize > (SourceLength * 10) then
BufferSize := SourceLength * 10;
except
//Oops, integer overflow! Better start with a string
//of the same size as the source.
BufferSize := SourceLength;
end;
SetLength(Result, BufferSize);
ResultPChar := @Result[1];
//Set up the pointers to S and SourceString
SPChar := @S[1];
SourceStringPChar := @SourceString[1];
PrevSourceStringPChar := SourceStringPChar;
FinalSourceMarker := @SourceString[SourceLength - (FindLength - 1)];
//Set up the pointer to FindString
FindPChar := @FindString[1];
//Set the pointer to ReplaceString
if ReplaceLength > 0 then
ReplacePChar := @NewPattern[1]
else
ReplacePChar := nil;
//Replace routine
repeat
//Find the sub string
SourceStringPChar := AnsiStrPos(PrevSourceStringPChar,
FindPChar);
if SourceStringPChar = nil then
Break;
//How many characters do we need to copy before
//the string occurs
CopySize := SourceStringPChar - PrevSourceStringPChar;
//Check we have enough space in our Result buffer
if CopySize + ReplaceLength > BufferSize - BytesWritten then
begin
BufferSize := Trunc(BufferSize * cDeltaSize);
SetLength(Result, BufferSize);
ResultPChar := @Result[BytesWritten + 1];
end;
//Copy the preceeding characters to our result buffer
Move(SPChar^, ResultPChar^, CopySize);
Inc(BytesWritten, CopySize);
//Advance the copy position of S
Inc(SPChar, CopySize + FindLength);
//Advance the Result pointer
Inc(ResultPChar, CopySize);
//Copy the replace string into the Result buffer
if Assigned(ReplacePChar) then
begin
Move(ReplacePChar^, ResultPChar^, ReplaceLength);
Inc(ResultPChar, ReplaceLength);
Inc(BytesWritten, ReplaceLength);
end;
//Fake delete the start of the source string
PrevSourceStringPChar := SourceStringPChar + FindLength;
until (PrevSourceStringPChar > FinalSourceMarker) or
not (rfReplaceAll in Flags);
FinalSourcePosition := Integer(SPChar - @S[1]);
CopySize := SourceLength - FinalSourcePosition;
SetLength(Result, BytesWritten + CopySize);
if CopySize > 0 then
Move(SPChar^, Result[BytesWritten + 1], CopySize);
end;
function FastReplace(const aSourceString: string; const aFindString,
aReplaceString: string;
CaseSensitive: Boolean = False): string;
var
PResult : PChar;
PReplace : PChar;
PSource : PChar;
PFind : PChar;
PPosition : PChar;
CurrentPos,
BytesUsed,
lResult,
lReplace,
lSource,
lFind : Integer;
Find : TFastPosProc;
CopySize : Integer;
JumpTable : TBMJumpTable;
begin
LSource := Length(aSourceString);
if LSource = 0 then
begin
Result := aSourceString;
exit;
end;
PSource := @aSourceString[1];
LFind := Length(aFindString);
if LFind = 0 then
exit;
PFind := @aFindString[1];
LReplace := Length(aReplaceString);
//Here we may get an Integer Overflow, or OutOfMemory, if so, we use a Delta
try
if LReplace <= LFind then
SetLength(Result, lSource)
else
SetLength(Result, (LSource * LReplace) div LFind);
except
SetLength(Result, 0);
end;
LResult := Length(Result);
if LResult = 0 then
begin
LResult := Trunc((LSource + LReplace) * cDeltaSize);
SetLength(Result, LResult);
end;
PResult := @Result[1];
if CaseSensitive then
begin
MakeBMTable(PChar(AFindString), lFind, JumpTable);
Find := BMPos;
end
else
begin
MakeBMTableNoCase(PChar(AFindString), lFind, JumpTable);
Find := BMPosNoCase;
end;
BytesUsed := 0;
if LReplace > 0 then
begin
PReplace := @aReplaceString[1];
repeat
PPosition := Find(PSource, PFind, lSource, lFind, JumpTable);
if PPosition = nil then
break;
CopySize := PPosition - PSource;
Inc(BytesUsed, CopySize + LReplace);
if BytesUsed >= LResult then
begin
//We have run out of space
CurrentPos := Integer(PResult) - Integer(@Result[1]) + 1;
LResult := Trunc(LResult * cDeltaSize);
SetLength(Result, LResult);
PResult := @Result[CurrentPos];
end;
FastCharMove(PSource^, PResult^, CopySize);
Dec(lSource, CopySize + LFind);
Inc(PSource, CopySize + LFind);
Inc(PResult, CopySize);
FastCharMove(PReplace^, PResult^, LReplace);
Inc(PResult, LReplace);
until lSource < lFind;
end
else
begin
repeat
PPosition := Find(PSource, PFind, lSource, lFind, JumpTable);
if PPosition = nil then
break;
CopySize := PPosition - PSource;
FastCharMove(PSource^, PResult^, CopySize);
Dec(lSource, CopySize + LFind);
Inc(PSource, CopySize + LFind);
Inc(PResult, CopySize);
Inc(BytesUsed, CopySize);
until lSource < lFind;
end;
SetLength(Result, (PResult + LSource) - @Result[1]);
if LSource > 0 then
FastCharMove(PSource^, Result[BytesUsed + 1], LSource);
end;
function FastTagReplace(const SourceString, TagStart, TagEnd: string;
FastTagReplaceProc: TFastTagReplaceProc; const UserData: Integer): string;
var
TagStartPChar : PChar;
TagEndPChar : PChar;
SourceStringPChar : PChar;
TagStartFindPos : PChar;
TagEndFindPos : PChar;
TagStartLength : Integer;
TagEndLength : Integer;
DestPChar : PChar;
FinalSourceMarkerStart: PChar;
FinalSourceMarkerEnd: PChar;
BytesWritten : Integer;
BufferSize : Integer;
CopySize : Integer;
ReplaceString : string;
procedure AddBuffer(const Buffer: Pointer; Size: Integer);
begin
if BytesWritten + Size > BufferSize then
begin
BufferSize := Trunc(BufferSize * cDeltaSize);
if BufferSize <= (BytesWritten + Size) then
BufferSize := Trunc((BytesWritten + Size) * cDeltaSize);
SetLength(Result, BufferSize);
DestPChar := @Result[BytesWritten + 1];
end;
Inc(BytesWritten, Size);
FastCharMove(Buffer^, DestPChar^, Size);
DestPChar := DestPChar + Size;
end;
begin
Assert(Assigned(@FastTagReplaceProc));
TagStartPChar := PChar(TagStart);
TagEndPChar := PChar(TagEnd);
if (SourceString = '') or (TagStart = '') or (TagEnd = '') then
begin
Result := SourceString;
Exit;
end;
SourceStringPChar := PChar(SourceString);
TagStartLength := Length(TagStart);
TagEndLength := Length(TagEnd);
FinalSourceMarkerEnd := SourceStringPChar + Length(SourceString) -
TagEndLength;
FinalSourceMarkerStart := FinalSourceMarkerEnd - TagStartLength;
BytesWritten := 0;
BufferSize := Length(SourceString);
SetLength(Result, BufferSize);
DestPChar := @Result[1];
repeat
TagStartFindPos := AnsiStrPos(SourceStringPChar, TagStartPChar);
if (TagStartFindPos = nil) or (TagStartFindPos > FinalSourceMarkerStart)
then
Break;
TagEndFindPos := AnsiStrPos(TagStartFindPos + TagStartLength, TagEndPChar);
if (TagEndFindPos = nil) or (TagEndFindPos > FinalSourceMarkerEnd) then
Break;
CopySize := TagStartFindPos - SourceStringPChar;
AddBuffer(SourceStringPChar, CopySize);
CopySize := TagEndFindPos - (TagStartFindPos + TagStartLength);
SetLength(ReplaceString, CopySize);
if CopySize > 0 then
Move((TagStartFindPos + TagStartLength)^, ReplaceString[1], CopySize);
FastTagReplaceProc(ReplaceString, UserData);
if Length(ReplaceString) > 0 then
AddBuffer(@ReplaceString[1], Length(ReplaceString));
SourceStringPChar := TagEndFindPos + TagEndLength;
until SourceStringPChar > FinalSourceMarkerStart;
CopySize := PChar(@SourceString[Length(SourceString)]) - (SourceStringPChar -
1);
if CopySize > 0 then
AddBuffer(SourceStringPChar, CopySize);
SetLength(Result, BytesWritten);
end;
function SmartPos(const SearchStr, SourceStr: string;
const CaseSensitive: Boolean = TRUE;
const StartPos: Integer = 1;
const ForwardSearch: Boolean = TRUE): Integer;
begin
// NOTE: When using StartPos, the returned value is absolute!
if (CaseSensitive) then
if (ForwardSearch) then
Result :=
FastPos(SourceStr, SearchStr, Length(SourceStr), Length(SearchStr),
StartPos)
else
Result :=
FastPosBack(SourceStr, SearchStr, Length(SourceStr), Length(SearchStr),
StartPos)
else if (ForwardSearch) then
Result :=
FastPosNoCase(SourceStr, SearchStr, Length(SourceStr), Length(SearchStr),
StartPos)
else
Result :=
FastPosBackNoCase(SourceStr, SearchStr, Length(SourceStr),
Length(SearchStr), StartPos)
end;
var
I : Integer;
initialization
{$IFNDEF LINUX}
for I := 0 to 255 do
GUpcaseTable[I] := Chr(I);
CharUpperBuff(@GUpcaseTable[0], 256);
{$ELSE}
for I := 0 to 255 do
GUpcaseTable[I] := UpCase(Chr(I));
{$ENDIF}
GUpcaseLUT := @GUpcaseTable[0];
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -