我希望有汇编语言经验的人能帮我写一个 Delphi 函数,如果字符串以 Chr(127) 开头,则忽略该字符串的第一个字符。这个函数用于排序比较,当比较 30,000 个条目时,由于必须在比较之前从第二个字符复制文本,因此速度非常慢。这是原始函数。
function CompareText(const S1, S2: string): Integer; assembler;
asm
PUSH ESI
PUSH EDI
PUSH EBX
MOV ESI,EAX
MOV EDI,EDX
OR EAX,EAX
JE @@0
MOV EAX,[EAX-4]
@@0: OR EDX,EDX
JE @@1
MOV EDX,[EDX-4]
@@1: MOV ECX,EAX
CMP ECX,EDX
JBE @@2
MOV ECX,EDX
@@2: CMP ECX,ECX
@@3: REPE CMPSB
JE @@6
MOV BL,BYTE PTR [ESI-1]
CMP BL,'a'
JB @@4
CMP BL,'z'
JA @@4
SUB BL,20H
@@4: MOV BH,BYTE PTR [EDI-1]
CMP BH,'a'
JB @@5
CMP BH,'z'
JA @@5
SUB BH,20H
@@5: CMP BL,BH
JE @@3
MOVZX EAX,BL
MOVZX EDX,BH
@@6: SUB EAX,EDX
POP EBX
POP EDI
POP ESI
end;
如果您能帮忙的话非常感谢。
我当然明白“在比较之前必须从第二个字符开始复制文本”会非常慢。
你不需要复制任何东西。在 Chr(127) 的情况下,你只需将字符串中的第二个位置视为其真正的起始位置即可。在代码中,这意味着增加 ESI/EDI 的地址,同时减少 EAX/EDX 的长度。
为了获得更好的性能,不要使用 BL 和 BH,而是使用完整的 32 位寄存器,即使这意味着保留像 EBP 这样的额外寄存器。
我确信循环,特别是它的 LCase 部分可以进一步优化,但我认为忽略前导 Chr(127) 的主要问题已经解决了……
有一个小算法问题
你的主循环 (
@@3
) 本质上包含两部分:一部分进行“按原样”比较 ( ),另一部分进行“不区分大小写”比较。如果后者是循环中唯一的部分cmpsb
,那么它就有意义,但是,与第一部分结合,它应该只用于确认为字母的当前字节。我不知道您的任何字符串是否包含从 91 到 96 范围内的 ASCII 代码,但如果是这样的话,那么目前您的原始代码可能会因 UCase 的发生而错误地报告来自 [a,z] 的任何字符串和来自 ]Z,a[ 的任何字符串之间的比较,同样,由于 LCase 的发生,我的第一个代码也可能因 LCase 的发生而错误地报告来自 [A,Z] 的任何字符串和来自 ]Z,a[ 的任何字符串之间的比较。
这是修改后的代码:
顺便说一句,既然我已经应用了 Peter 在评论中提到的技术,新代码应该运行得更快。