Another_eYes写的FastPos函数

来源:互联网 发布:xy坐标转换经纬度软件 编辑:程序博客网 时间:2024/05/17 03:12
  1. //Another_eYes
  2. //详见ID:328122为DFW的帖子
  3. Type
  4.   TFastPosProc = function (TagStr, SrcStr: PChar;
  5.         TagCount: Integer; var SrcCount: Integer): Integer;
  6. function FastPos(TagStr, SrcStr: PChar; TagCount: Integer;
  7.     var SrcCount: Integer): PChar; assembler;
  8. asm
  9. // 进入程序时, TagStr在EAX, SrcStr在EBX, TagCount在ECX
  10.          PUSH         ESI
  11.          PUSH         EDI
  12.          PUSH         EBX
  13.          PUSH         EBP
  14.          MOV          ESI, EAX    // EAX = TagStr
  15.          MOV          EDI, EDX    // EDX = SrcStr
  16.          MOV          EDX, SrcCount  // EDX= SrcCount
  17.          AND          EDX, EDX     // SrcCount <= 0?
  18.          JLE          @NotFound    // Yes, not found
  19.          DEC          ECX          // 如果第一个字符匹配时 需要比较的字节数
  20.          JL           @NotFound    // TagCount < 0? Yes-> not found
  21.          SUB          EDX, ECX     // else 计算需要搜索的SrcStr长度
  22.                                    // 此长度=SrcCount - TagCount + 1
  23.          JLE          @NotFound    // SrcCount < TagCount ? Yes-> not found
  24.          LODSB                       //  AL = TagStr[1]  ESI指向下一个字节
  25.          MOV          AH, CL         //保存当前TagStr长度mod 4的尾数
  26.          AND          AH, 3          // 到AH中
  27.          SHR          ECX, 1      
  28.          SHR          ECX, 1
  29.          MOV          EBP, ECX       // 按4字节算的长度, 保存在EBP
  30.          MOV          ECX, EDX       // ECX=SrcCount
  31. @StartFind:
  32.          REPNZ        SCASB          // 搜索第一个字符
  33.          JNZ          @NotFound      // 找不到
  34.          MOV          EDX, ECX       // 保存剩余的SrcCount
  35.          MOV          ECX, EBP       // 取得TagStr长度
  36.          MOV          EBX, EDI       //保存当前SrcStr地址
  37.          REPZ         CMPSD          // 按4字节为单位比较比较Src和Tag
  38.          JNZ          @FindNext      // 不相等
  39.          XOR          ECX, ECX       // ECX清0
  40.          MOV          CL, AH
  41.          REPZ         CMPSB          // 剩下的字节进行比较
  42.          JNZ          @FindNext      // 不相等
  43. // 找到了, 返回找到的地址, 并修改SrcCount变量(已经去掉了匹配字符串的长度)
  44.          DEC          EDX            // 程序开始时多算一个字节, 现在去掉
  45.          MOV          SrcCount, EDX
  46.          MOV          EAX, EBX       // 匹配起始地址, 未包含第一个字符
  47.          DEC          EAX            // 包含进第一个匹配字符
  48.          JMP          @Found
  49. @FindNext:
  50.          MOV          ESI, SrcStr
  51.          INC          ESI            // 恢复参数准备查找下一轮匹配的字符
  52.          MOV          ECX, EDX
  53.          MOV          EDI, EBX
  54.          JMP          @StartFind
  55. @NotFound:
  56.          XOR          EAX, EAX       // 未找到, 返回 0, 并且SrcCount不变
  57. @Found:
  58.          POP          EBP
  59.          POP          EBX
  60.          POP          EDI
  61.          POP          ESI
  62. end;
  63. function FastPosNoCase(Tag, Src: PChar; TagCount: Integer;
  64.     var SrcCount: Integer): PChar; assembler;
  65. asm
  66.          PUSH         ESI
  67.          PUSH         EDI
  68.          PUSH         EBX
  69.          MOV          EDI, EAX    // EAX = Tag
  70.          MOV          ESI, EDX    // EDX = Src
  71.          MOV          EDX, SrcCount
  72.          XCHG         EDX, ECX     // 结果: ECX = SrcCount EDX = TagCount
  73.          DEC          EDX          // 找到第一个字符后需要匹配的个数
  74.          JL           @NotFound    // TagCount <= 0 ?
  75.          OR           ECX, ECX     // SrcCount <= 0 ?
  76.          JLE          @NotFound
  77.          SUB          ECX, EDX
  78.          JLE          @NotFound    // SrcCount < TagCount ?
  79.          MOV          AH, [EDI]    // 取第一个字符进行查找
  80.          INC          EDI
  81.          CMP          AH, 97
  82.          JB           @StartScan   // < 'a' ?
  83.          CMP          AH, 122      // > 'z' ?
  84.          JA           @StartScan
  85.          SUB          AH, 32       // 转大写
  86. @StartScan:
  87.          OR           ECX, ECX
  88.          JZ           @NotFound
  89.          LODSB
  90.          CMP          AL, 97
  91.          JB           @@1
  92.          CMP          AL, 122
  93.          JA           @@1
  94.          SUB          AL, 32       // 转大写
  95. @@1:
  96.          CMP          AH, AL
  97.          JZ           @CmpStr
  98.          DEC          CX
  99.          JNZ          @StartScan
  100.          JMP          @NotFound
  101. @CmpStr:
  102.          DEC          ECX
  103.          MOV          EBX, EDX
  104.          SHL          EAX, 16      // 保存AH
  105. @ContinueCompare:
  106.          MOV          AH, [ESI + EBX]
  107.          CMP          AH, 97
  108.          JB           @@2
  109.          CMP          AH, 122
  110.          JA           @@2
  111.          SUB          AH, 32
  112. @@2:
  113.          MOV          AL, [EDI+EBX]
  114.          CMP          AL, 97
  115.          JB           @@3
  116.          CMP          AL, 122
  117.          JA           @@3
  118.          SUB          AL, 32
  119. @@3:
  120.          CMP          AH, AL
  121.          JNZ          @FindNext
  122.          DEC          EBX
  123.          JG           @ContinueCompare
  124. @Found:
  125.          DEC          ECX
  126.          MOV          SrcCount, ECX
  127.          MOV          EAX, ESI
  128.          DEC          EAX
  129.          JMP          @OutPoint
  130. @NotFound:
  131.          XOR          EAX, EAX
  132.          JMP          @OutPoint
  133. @FindNext:
  134.          SHR          EAX, 16         // 恢复AH
  135.          JMP          @StartScan
  136. @OutPoint:
  137.          POP          EBX
  138.          POP          EDI
  139.          POP          ESI
  140. end;
  141. function FastReplace(var Target: string; FindStr: string; ReplaceStr: string;
  142.   CaseSensitive: Boolean = True): Integer;
  143.                            // Target: 需要进行替换操作的字符串
  144.                            // FindStr: 要替换的字符串
  145.                            // ReplaceStr: 替换成
  146.                            // CaseSensitive: 是否大小写区分, 默认True (速度快)
  147.                            // 返回值: 共替换了几个字符串
  148. var
  149.   MaxCnt: Integer;    // 保存匹配位置缓冲区的大小
  150.   MatchPoses: array of Integer;  // 缓冲区, 保存所有匹配的位置
  151.   AdjustLen: Integer;  // 最后需要调整Target的大小
  152.   n,                   // 当前匹配位置
  153.   l1,                  // Target的原始长度
  154.   l2,                  // FindStr的长度
  155.   l3,                  // ReplaceStr的长度
  156.   l: Integer;          // 当前剩余需要匹配字符数
  157.   Proc: TFastPosProc;  // 查找过程(大小写区分用FastPos, 不区分用FastPosNoCase)
  158. begin
  159.   Result := 0;
  160.   l1 := Length(Target);
  161.   l2 := Length(FindStr);
  162.   l3 := Length(ReplaceStr);
  163.   if (l1 = 0or (l2 = 0then Exit;
  164.   AdjustLen := 0;
  165.   MaxCnt:=0;
  166.   l := l1;
  167.   if CaseSensitive then
  168.     Proc := @FastPos
  169.   else
  170.     Proc := @FastPosNoCase;
  171.   // 找出所有匹配字符串的位置, 并填到MatchPoses数组中
  172.   n := Integer(PChar(Target));
  173.   while (n <> 0do
  174.   begin
  175.     n := Integer(Proc(PChar(FindStr), Ptr(n), l2, l));
  176.     if n <> 0 then
  177.     begin
  178.       if Result >= MaxCnt then             // 超过缓冲区大小?
  179.       begin
  180.         MaxCnt := MaxCnt + 256;          // 扩展缓冲区
  181.         SetLength(MatchPoses, MaxCnt);
  182.       end;
  183.       MatchPoses[Result] := n + AdjustLen;  // 完成替换后在字符串中的位置
  184.       Inc(AdjustLen, l3 - l2);
  185.       Inc(Result);
  186.       Inc(n, l2);
  187.     end;
  188.   end;
  189.   if Result = 0 then Exit; // 未找到匹配
  190.   if AdjustLen > 0 then    // 新字串比老字串长
  191.   begin
  192.     SetLength(Target, l1 + AdjustLen);  // 分配内存
  193.                                         // 因为新字串比老字串长
  194.                                         // 因此复制字串时将从尾部开始
  195.     asm
  196.           PUSH        ESI
  197.           PUSH        EDI
  198.           PUSH        EBX
  199.           PUSH        EBP               // 保存现场
  200.           MOV         EAX, ReplaceStr
  201.           ADD         EAX, L3
  202.           DEC         EAX               // ReplaceStr的结尾地址
  203.           MOV         EBP, EAX          // 保存
  204.           MOV         EDX, MatchPoses   // EDX将指向MatchPoses中最后一个替换
  205.           MOV         EAX, Result
  206.           MOV         EBX, EAX          // EBX 保存需要替换的次数
  207.           DEC         EAX
  208.           SHL         EAX, 1
  209.           SHL         EAX, 1
  210.           ADD         EDX, EAX          //  EDX 定位到MatchPoses[Result-1]
  211.           MOV         ESI, Target
  212.           ADD         ESI, L1
  213.           DEC         ESI               // 原Target结尾处
  214.           MOV         EDI, ESI
  215.           ADD         EDI, AdjustLen    // 新Target结尾处
  216.           STD                           // 设置方向标志: 从尾到头
  217.     @@1:
  218.           MOV         ECX, EDI
  219.           LEA         EAX, [EDX]
  220.           ADD         EAX, L3
  221.           DEC         EAX
  222.           SUB         ECX, EAX          // ECX为两个要替换字符串中间的字符数
  223.           MOV         EAX, ECX
  224.           SHR         ECX, 1
  225.           SHR         ECX, 1
  226.           REP         MOVSD
  227.           MOV         ECX, EAX
  228.           AND         ECX, 3
  229.           REP         MOVSB             // 复制原字符串
  230.           MOV         EAX, ESI          // 保存当前原串位置到EAX
  231.           SUB         EAX, L2           // 调整位置跳过需要被替换的字符串
  232.           MOV         ESI, EBP          // ESI指向替换成的字符串
  233.           MOV         ECX, L3           // 长度
  234.           SHR         ECX, 1
  235.           SHR         ECX, 1
  236.           REP         MOVSD
  237.           MOV         ECX, L3
  238.           AND         ECX, 3
  239.           REP         MOVSB             // 复制新串到相应位置
  240.           SUB         EDX, 4            // 下一个要替换的位置
  241.           MOV         ESI, EAX          // 恢复原串位置
  242.           DEC         EBX
  243.           JNZ         @@1               // 替换已完成?
  244.                                         // 因为是倒序, 所以第一个需要
  245.                                         // 替换的字符串前的原始串不会
  246.                                         // 改变, 没有必要再进行复制
  247.           CLD                           // 清方向标志
  248.           POP         EBP
  249.           POP         EBX
  250.           POP         EDI
  251.           POP         ESI               // 恢复现场
  252.     end;
  253.   end
  254.   else if AdjustLen < 0 then            // 因为是缩短Target, 所以先进行
  255.                                         // 替换与复制, 然后再调整内存
  256.   begin
  257.     asm
  258.           PUSH        ESI
  259.           PUSH        EDI
  260.           PUSH        EBX
  261.           PUSH        EBP               // 保存现场
  262.           MOV         EAX, ReplaceStr
  263.           ADD         EAX, L1
  264.           ADD         EAX, AdjustLen
  265.           PUSH        EAX               // 保存字符串的结尾(为计算最后一次替换
  266.                                         // 后还需要复制多少字节做准备)
  267.           MOV         EBX, Result
  268.           MOV         EDX, MatchPoses   // EDX指向MatchPoses[0]
  269.           LEA         ESI, [EDX]
  270.           MOV         EDI, ESI
  271.           JMP         @@2               // 第一次替换发生前的部分不需要进行复制
  272.     @@1:
  273.           LEA         ECX, [EDX]
  274.           SUB         ECX, EDI          // 两次替换之间需要复制的字符数
  275.           MOV         EAX, ECX
  276.           SHR         ECX, 1
  277.           SHR         ECX, 1
  278.           REP         MOVSD
  279.           MOV         ECX, EAX
  280.           AND         ECX, 3
  281.           REP         MOVSB             // 复制
  282.     @@2:
  283.           MOV         EAX, ESI
  284.           ADD         EAX, L2           // 跳过原串中被替换字符串后的位置保存在EAX
  285.           MOV         ESI, ReplaceStr
  286.           MOV         ECX, L3
  287.           MOV         EBP, ECX
  288.           SHR         ECX, 1
  289.           SHR         ECX, 1
  290.           REP         MOVSD
  291.           MOV         ECX, EBP
  292.           AND         ECX, 3
  293.           REP         MOVSB          // 替换
  294.           MOV         ESI, EAX       // 恢复ESI到下一次需要移动或替换的位置
  295.           ADD         EDX, 4         // EDX指向MatchPoses[i+1]
  296.           DEC         EBX            // 所有替换都已经完成?
  297.           JNZ         @@1
  298.           POP         ECX
  299.           SUB         ECX, EDI       // 最后一次替换后需要复制的字节数
  300.           MOV         EBP, ECX
  301.           SHR         ECX, 1
  302.           SHR         ECX, 1
  303.           REP         MOVSD
  304.           MOV         ECX, EBP
  305.           AND         ECX, 3
  306.           REP         MOVSB          // 复制
  307.           POP         EBP
  308.           POP         EBX
  309.           POP         EDI
  310.           POP         ESI            // 恢复现场
  311.     end;
  312.     SetLength(Target, l1 + AdjustLen);
  313.   end
  314.   else begin                          // 字符串长度不变时
  315.                                       // 只需要进行替换而不必复制了
  316.     asm
  317.           PUSH        ESI
  318.           PUSH        EDI
  319.           PUSH        EBX
  320.           PUSH        EBP
  321.           MOV         EBX, ReplaceStr //EBX 保存ReplaceStr地址
  322.           MOV         EDX, MatchPoses
  323.           MOV         EAX, Result
  324.           MOV         EBP, L3
  325.     @@1:
  326.           LEA         EDI, [EDX]
  327.           MOV         ESI, EBX       // 比 MOV    ESI, ReplaceStr快
  328.           MOV         ECX, EBP
  329.           SHR         ECX, 1
  330.           SHR         ECX, 1
  331.           REP         MOVSD
  332.           MOV         ECX, EBP
  333.           AND         ECX, 3
  334.           REP         MOVSB
  335.           ADD         EDX, 4
  336.           DEC         EAX
  337.           JNZ         @@1
  338.           POP         EBP
  339.           POP         EBX
  340.           POP         EDI
  341.           POP         ESI
  342.     end;
  343.   end;
  344. end;
原创粉丝点击