- //Another_eYes
- //详见ID:328122为DFW的帖子
- Type
- TFastPosProc = function (TagStr, SrcStr: PChar;
- TagCount: Integer; var SrcCount: Integer): Integer;
- function FastPos(TagStr, SrcStr: PChar; TagCount: Integer;
- var SrcCount: Integer): PChar; assembler;
- asm
- // 进入程序时, TagStr在EAX, SrcStr在EBX, TagCount在ECX
- PUSH ESI
- PUSH EDI
- PUSH EBX
- PUSH EBP
- MOV ESI, EAX // EAX = TagStr
- MOV EDI, EDX // EDX = SrcStr
- MOV EDX, SrcCount // EDX= SrcCount
- AND EDX, EDX // SrcCount <= 0?
- JLE @NotFound // Yes, not found
- DEC ECX // 如果第一个字符匹配时 需要比较的字节数
- JL @NotFound // TagCount < 0? Yes-> not found
- SUB EDX, ECX // else 计算需要搜索的SrcStr长度
- // 此长度=SrcCount - TagCount + 1
- JLE @NotFound // SrcCount < TagCount ? Yes-> not found
- LODSB // AL = TagStr[1] ESI指向下一个字节
- MOV AH, CL //保存当前TagStr长度mod 4的尾数
- AND AH, 3 // 到AH中
- SHR ECX, 1
- SHR ECX, 1
- MOV EBP, ECX // 按4字节算的长度, 保存在EBP
- MOV ECX, EDX // ECX=SrcCount
- @StartFind:
- REPNZ SCASB // 搜索第一个字符
- JNZ @NotFound // 找不到
- MOV EDX, ECX // 保存剩余的SrcCount
- MOV ECX, EBP // 取得TagStr长度
- MOV EBX, EDI //保存当前SrcStr地址
- REPZ CMPSD // 按4字节为单位比较比较Src和Tag
- JNZ @FindNext // 不相等
- XOR ECX, ECX // ECX清0
- MOV CL, AH
- REPZ CMPSB // 剩下的字节进行比较
- JNZ @FindNext // 不相等
- // 找到了, 返回找到的地址, 并修改SrcCount变量(已经去掉了匹配字符串的长度)
- DEC EDX // 程序开始时多算一个字节, 现在去掉
- MOV SrcCount, EDX
- MOV EAX, EBX // 匹配起始地址, 未包含第一个字符
- DEC EAX // 包含进第一个匹配字符
- JMP @Found
- @FindNext:
- MOV ESI, SrcStr
- INC ESI // 恢复参数准备查找下一轮匹配的字符
- MOV ECX, EDX
- MOV EDI, EBX
- JMP @StartFind
- @NotFound:
- XOR EAX, EAX // 未找到, 返回 0, 并且SrcCount不变
- @Found:
- POP EBP
- POP EBX
- POP EDI
- POP ESI
- end;
- function FastPosNoCase(Tag, Src: PChar; TagCount: Integer;
- var SrcCount: Integer): PChar; assembler;
- asm
- PUSH ESI
- PUSH EDI
- PUSH EBX
- MOV EDI, EAX // EAX = Tag
- MOV ESI, EDX // EDX = Src
- MOV EDX, SrcCount
- XCHG EDX, ECX // 结果: ECX = SrcCount EDX = TagCount
- DEC EDX // 找到第一个字符后需要匹配的个数
- JL @NotFound // TagCount <= 0 ?
- OR ECX, ECX // SrcCount <= 0 ?
- JLE @NotFound
- SUB ECX, EDX
- JLE @NotFound // SrcCount < TagCount ?
- MOV AH, [EDI] // 取第一个字符进行查找
- INC EDI
- CMP AH, 97
- JB @StartScan // < 'a' ?
- CMP AH, 122 // > 'z' ?
- JA @StartScan
- SUB AH, 32 // 转大写
- @StartScan:
- OR ECX, ECX
- JZ @NotFound
- LODSB
- CMP AL, 97
- JB @@1
- CMP AL, 122
- JA @@1
- SUB AL, 32 // 转大写
- @@1:
- CMP AH, AL
- JZ @CmpStr
- DEC CX
- JNZ @StartScan
- JMP @NotFound
- @CmpStr:
- DEC ECX
- MOV EBX, EDX
- SHL EAX, 16 // 保存AH
- @ContinueCompare:
- MOV AH, [ESI + EBX]
- CMP AH, 97
- JB @@2
- CMP AH, 122
- JA @@2
- SUB AH, 32
- @@2:
- MOV AL, [EDI+EBX]
- CMP AL, 97
- JB @@3
- CMP AL, 122
- JA @@3
- SUB AL, 32
- @@3:
- CMP AH, AL
- JNZ @FindNext
- DEC EBX
- JG @ContinueCompare
- @Found:
- DEC ECX
- MOV SrcCount, ECX
- MOV EAX, ESI
- DEC EAX
- JMP @OutPoint
- @NotFound:
- XOR EAX, EAX
- JMP @OutPoint
- @FindNext:
- SHR EAX, 16 // 恢复AH
- JMP @StartScan
- @OutPoint:
- POP EBX
- POP EDI
- POP ESI
- end;
- function FastReplace(var Target: string; FindStr: string; ReplaceStr: string;
- CaseSensitive: Boolean = True): Integer;
- // Target: 需要进行替换操作的字符串
- // FindStr: 要替换的字符串
- // ReplaceStr: 替换成
- // CaseSensitive: 是否大小写区分, 默认True (速度快)
- // 返回值: 共替换了几个字符串
- var
- MaxCnt: Integer; // 保存匹配位置缓冲区的大小
- MatchPoses: array of Integer; // 缓冲区, 保存所有匹配的位置
- AdjustLen: Integer; // 最后需要调整Target的大小
- n, // 当前匹配位置
- l1, // Target的原始长度
- l2, // FindStr的长度
- l3, // ReplaceStr的长度
- l: Integer; // 当前剩余需要匹配字符数
- Proc: TFastPosProc; // 查找过程(大小写区分用FastPos, 不区分用FastPosNoCase)
- begin
- Result := 0;
- l1 := Length(Target);
- l2 := Length(FindStr);
- l3 := Length(ReplaceStr);
- if (l1 = 0) or (l2 = 0) then Exit;
- AdjustLen := 0;
- MaxCnt:=0;
- l := l1;
- if CaseSensitive then
- Proc := @FastPos
- else
- Proc := @FastPosNoCase;
- // 找出所有匹配字符串的位置, 并填到MatchPoses数组中
- n := Integer(PChar(Target));
- while (n <> 0) do
- begin
- n := Integer(Proc(PChar(FindStr), Ptr(n), l2, l));
- if n <> 0 then
- begin
- if Result >= MaxCnt then // 超过缓冲区大小?
- begin
- MaxCnt := MaxCnt + 256; // 扩展缓冲区
- SetLength(MatchPoses, MaxCnt);
- end;
- MatchPoses[Result] := n + AdjustLen; // 完成替换后在字符串中的位置
- Inc(AdjustLen, l3 - l2);
- Inc(Result);
- Inc(n, l2);
- end;
- end;
- if Result = 0 then Exit; // 未找到匹配
- if AdjustLen > 0 then // 新字串比老字串长
- begin
- SetLength(Target, l1 + AdjustLen); // 分配内存
- // 因为新字串比老字串长
- // 因此复制字串时将从尾部开始
- asm
- PUSH ESI
- PUSH EDI
- PUSH EBX
- PUSH EBP // 保存现场
- MOV EAX, ReplaceStr
- ADD EAX, L3
- DEC EAX // ReplaceStr的结尾地址
- MOV EBP, EAX // 保存
- MOV EDX, MatchPoses // EDX将指向MatchPoses中最后一个替换
- MOV EAX, Result
- MOV EBX, EAX // EBX 保存需要替换的次数
- DEC EAX
- SHL EAX, 1
- SHL EAX, 1
- ADD EDX, EAX // EDX 定位到MatchPoses[Result-1]
- MOV ESI, Target
- ADD ESI, L1
- DEC ESI // 原Target结尾处
- MOV EDI, ESI
- ADD EDI, AdjustLen // 新Target结尾处
- STD // 设置方向标志: 从尾到头
- @@1:
- MOV ECX, EDI
- LEA EAX, [EDX]
- ADD EAX, L3
- DEC EAX
- SUB ECX, EAX // ECX为两个要替换字符串中间的字符数
- MOV EAX, ECX
- SHR ECX, 1
- SHR ECX, 1
- REP MOVSD
- MOV ECX, EAX
- AND ECX, 3
- REP MOVSB // 复制原字符串
- MOV EAX, ESI // 保存当前原串位置到EAX
- SUB EAX, L2 // 调整位置跳过需要被替换的字符串
- MOV ESI, EBP // ESI指向替换成的字符串
- MOV ECX, L3 // 长度
- SHR ECX, 1
- SHR ECX, 1
- REP MOVSD
- MOV ECX, L3
- AND ECX, 3
- REP MOVSB // 复制新串到相应位置
- SUB EDX, 4 // 下一个要替换的位置
- MOV ESI, EAX // 恢复原串位置
- DEC EBX
- JNZ @@1 // 替换已完成?
- // 因为是倒序, 所以第一个需要
- // 替换的字符串前的原始串不会
- // 改变, 没有必要再进行复制
- CLD // 清方向标志
- POP EBP
- POP EBX
- POP EDI
- POP ESI // 恢复现场
- end;
- end
- else if AdjustLen < 0 then // 因为是缩短Target, 所以先进行
- // 替换与复制, 然后再调整内存
- begin
- asm
- PUSH ESI
- PUSH EDI
- PUSH EBX
- PUSH EBP // 保存现场
- MOV EAX, ReplaceStr
- ADD EAX, L1
- ADD EAX, AdjustLen
- PUSH EAX // 保存字符串的结尾(为计算最后一次替换
- // 后还需要复制多少字节做准备)
- MOV EBX, Result
- MOV EDX, MatchPoses // EDX指向MatchPoses[0]
- LEA ESI, [EDX]
- MOV EDI, ESI
- JMP @@2 // 第一次替换发生前的部分不需要进行复制
- @@1:
- LEA ECX, [EDX]
- SUB ECX, EDI // 两次替换之间需要复制的字符数
- MOV EAX, ECX
- SHR ECX, 1
- SHR ECX, 1
- REP MOVSD
- MOV ECX, EAX
- AND ECX, 3
- REP MOVSB // 复制
- @@2:
- MOV EAX, ESI
- ADD EAX, L2 // 跳过原串中被替换字符串后的位置保存在EAX
- MOV ESI, ReplaceStr
- MOV ECX, L3
- MOV EBP, ECX
- SHR ECX, 1
- SHR ECX, 1
- REP MOVSD
- MOV ECX, EBP
- AND ECX, 3
- REP MOVSB // 替换
- MOV ESI, EAX // 恢复ESI到下一次需要移动或替换的位置
- ADD EDX, 4 // EDX指向MatchPoses[i+1]
- DEC EBX // 所有替换都已经完成?
- JNZ @@1
- POP ECX
- SUB ECX, EDI // 最后一次替换后需要复制的字节数
- MOV EBP, ECX
- SHR ECX, 1
- SHR ECX, 1
- REP MOVSD
- MOV ECX, EBP
- AND ECX, 3
- REP MOVSB // 复制
- POP EBP
- POP EBX
- POP EDI
- POP ESI // 恢复现场
- end;
- SetLength(Target, l1 + AdjustLen);
- end
- else begin // 字符串长度不变时
- // 只需要进行替换而不必复制了
- asm
- PUSH ESI
- PUSH EDI
- PUSH EBX
- PUSH EBP
- MOV EBX, ReplaceStr //EBX 保存ReplaceStr地址
- MOV EDX, MatchPoses
- MOV EAX, Result
- MOV EBP, L3
- @@1:
- LEA EDI, [EDX]
- MOV ESI, EBX // 比 MOV ESI, ReplaceStr快
- MOV ECX, EBP
- SHR ECX, 1
- SHR ECX, 1
- REP MOVSD
- MOV ECX, EBP
- AND ECX, 3
- REP MOVSB
- ADD EDX, 4
- DEC EAX
- JNZ @@1
- POP EBP
- POP EBX
- POP EDI
- POP ESI
- end;
- end;
- end;
Another_eYes写的FastPos函数
最新推荐文章于 2022-04-11 16:27:23 发布