📄 fstrrep.pas
字号:
//end------------------------------------------
// Make Al and Ah uppercase.
and Al, $df
//add by shengquanhu:just modified the lowercase 'a'..'z'
@LowerAh:
cmp Ah, $7A
ja @CompareChar2
cmp Ah, $61
jb @CompareChar2
//end------------------------------------------
and Ah, $df
@CompareChar2:
cmp Al, Ah
Jz @Matches
Mov Al, [ESI]
//add by shengquanhu:just modified the lowercase 'a'..'z'
cmp Al, $7A
ja @NextChar
cmp Al, $61
jb @NextChar
//end------------------------------------------
// Make Al uppercase.
and Al, $df
Jmp @NextChar
@Matches:
Dec EBX
Jnz @CompareNext
//add by Shengquanhu
@EndOfMatch:
//add end
mov EAX, EDI
sub EAX, aSourceString
inc EAX
mov Result, EAX
jmp @TheEnd
@NextChar:
Inc EDI
dec ECX
//add by shengquanhu
//if ah is chinese char,jump again
jz @Result0
cmp ah, $80
jb @ScaSB
Inc EDI
Dec ECX
//add by shengquanhu end
jnz @ScaSB
@Result0:
mov Result,0
@TheEnd:
pop EBX
pop EDI
pop ESI
end;
end;
//My move isn’t as fast as MOVE when source and destination are both DWord al
//igned, but it’s certainly faster when they’re not. As we’re moving charac
//ters in a string, it isn’t very likely at all that both source and destinat
//ion are DWord aligned, so moving bytes avoids the cycle penalty of reading/w
//riting DWords across physical boundaries.
procedure MyMove(
const Source; var Dest; Count : Integer);
asm
// Note: When this function is called,
// Delphi passes the parameters as follows:
// ECX = Count
// EAX = Const Source
// EDX = Var Dest
// If there are no bytes to copy, just quit
// altogether; there's no point pushing registers.
cmp ECX,0
Je @JustQuit
// Preserve the critical Delphi registers.
push ESI
push EDI
// Move Source into ESI (generally the
// SOURCE register).
// Move Dest into EDI (generally the DEST
// register for string commands).
// This might not actually be necessary,
// as I'm not using MOVsb etc.
// I might be able to just use EAX and EDX;
// there could be a penalty for not using
// ESI, EDI, but I doubt it.
// This is another thing worth trying!
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’s a hidden problem here. I won’t go into too much detail, but the Pe
//ntium can continue processing instructions while it’s still working out the
// result of INC ESI or INC EDI. If, however, you use them while they’re stil
//l being calculated, the processor will stop until they’re calculated (a pen
//alty). Therefore, I alter ESI and EDI as far in advance as possible of using
// them.
// Pop the critical Delphi registers
// that we've altered.
pop EDI
pop ESI
@JustQuit:
end;
//Point 1: I pass VAR aSourceString rather than just aSourceString. This is be
//cause I’ll just be passed a pointer to the data rather than a 10M copy of t
//he data itself, which is much quicker!
function FastReplace(
var aSourceString : String;
const aFindString, aReplaceString : String;
CaseSensitive : Boolean = False) : String;
var
// Size already passed to SetLength,
// the REAL size of RESULT.
ActualResultLen,
// Position of aFindString is aSourceString.
CurrentPos,
// Last position the aFindString was found at.
LastPos,
// Bytes to copy (that is, lastpos to this pos).
BytesToCopy,
// The "running" result length, not the actual one.
ResultLen,
// Length of aFindString, to save
// calling LENGTH repetitively.
FindLen,
// Length of aReplaceString, for the same reason.
ReplaceLen,
SourceLen : Integer;
// This is where I explain the
// TYPE TFastPosProc from earlier!
FastPosProc : TFastPosProc;
begin
//As this function has the option of being case-insensitive, I’d need to call
// either FastPOS or FastPOSNoCase. The problem is that you’d have to do this
// within a loop. This is a bad idea, since the result never changes throughou
//t the whole operation–in which case we can determine it in advance, like so
//:
if CaseSensitive then
FastPosProc := FastPOS
else
FastPOSProc := FastPOSNoCase;
// I don't think I actually need
// this, but I don't really mind!
Result := '';
// Get the lengths of the strings.
FindLen := Length(aFindString);
ReplaceLen := Length(aReplaceString);
SourceLen := Length(aSourceString);
// If we already have room for the replacements,
// then set the length of the result to
// the length of the SourceString.
if ReplaceLen <= FindLen then
ActualResultLen := SourceLen
else
// If not, we need to calculate the
// worst-case scenario.
// That is, the Source consists ONLY of
// aFindString, and we're going to replace
// every one of them!
ActualResultLen :=
SourceLen +
(SourceLen * ReplaceLen div FindLen) +
ReplaceLen;
// Set the length of Result; this
// will assign the memory, etc.
SetLength(Result,ActualResultLen);
CurrentPos := 1;
ResultLen := 0;
LastPos := 1;
//Again, I’m eliminating an IF statement in a loop by repeating code–this ap
//proach results in very slightly larger code, but if ever you can trade some
//memory in exchange for speed, go for it!
if ReplaceLen > 0 then begin
repeat
// Get the position of the first (or next)
// aFindString in aSourceString.
// Note that there's no If CaseSensitive,
// I just call FastPOSProc, which is pointing
// to the correct pre-determined routine.
CurrentPos :=
FastPosProc(aSourceString, aFindString,
SourceLen, FindLen, CurrentPos);
// If 0, then we're finished.
if CurrentPos = 0 then break;
// Number of bytes to copy from the
// source string is CurrentPos - lastPos,
// i.e. " cat " in "the cat the".
BytesToCopy := CurrentPos-LastPos;
// Copy chars from aSourceString
// to the end of Result.
MyMove(aSourceString[LastPos],
Result[ResultLen+1], BytesToCopy);
// Copy chars from aReplaceString to
// the end of Result.
MyMove(aReplaceString[1],
Result[ResultLen+1+BytesToCopy], ReplaceLen);
// Remember, using COPY would copy all of
// the data over and over again.
// Never fall into this trap (like a certain
// software company did).
// Set the running length to
ResultLen := ResultLen +
BytesToCopy + ReplaceLen;
// Set the position in aSourceString to where
// we want to continue searching from.
CurrentPos := CurrentPos + FindLen;
LastPos := CurrentPos;
until false;
end else begin
// You might have noticed If ReplaceLen > 0.
// Well, if ReplaceLen = 0, then we're deleting the
// substrings, rather than replacing them, so we
// don't need the extra MyMove from aReplaceString.
repeat
CurrentPos := FastPos(aSourceString,
aFindString, SourceLen, FindLen, CurrentPos);
if CurrentPos = 0 then break;
BytesToCopy := CurrentPos-LastPos;
MyMove(aSourceString[LastPos],
Result[ResultLen+1], BytesToCopy);
ResultLen := ResultLen +
BytesToCopy + ReplaceLen;
CurrentPos := CurrentPos + FindLen;
LastPos := CurrentPos;
until false;
end;
//Now that we’ve finished doing all of the replaces, I just need to adjust th
//e length of the final result:
Dec(LastPOS);
//Now I set the length to the Length plus the bit of string left. That is, " m
//at" when replacing "the" in "sat on the mat".
SetLength(Result, ResultLen + (SourceLen-LastPos));
// If there's a bit of string dangling, then
// add it to the end of our string.
if LastPOS+1 <= SourceLen then
MyMove(aSourceString[LastPos+1],
Result[ResultLen+1],SourceLen-LastPos);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -