所以,我有一个代码块设置边界来检查一个字符是否是字母(不是数字,不是符号),但我不认为它适用于大小写之间的字符。你能帮忙吗?谢谢!
mov al, byte ptr[esi + ecx]; move the first character to al
cmp al, 0 ; compare al with null which is the end of string
je done ; if yes, jump to done
cmp al, 0x41 ; compare al with "A" (upper bounder)
jl next_char ; jump to next character if less
cmp al, 0x7A ; compare al with "z" (lower bounder)
jg next_char ; jump to next character if greater
//do something if it's a letter
next_char:
//do something different
4条答案
按热度按时间cpjpxq1n1#
您可以或0x 20到每个字符;这将使大写字母变为小写字母(并将非字母字符替换为其他非字母字符):
注意:如果你的代码要处理0x 7 F以上的字母(如“",“П",“П”),它会变得非常复杂。在这种情况下,一个问题是这些字符的ASCII码在Windows控制台程序中是不同的(例如:“= 0x 8 E)和Windows GUI程序(“= 0xC 4),在其他操作系统中甚至可能有所不同...
wgmfuz8q2#
您需要有一个组合多个条件的逻辑,类似于"C"语句:
if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
你可以这样做:
hsvhsicv3#
正确,
'Z'
和'a'
之间有一些非字母字符的间隙。最有效的方法是用OR设置小写位,然后使用sub + unsigned compare的范围检查技巧。当然,这只适用于ASCII,不适用于扩展字符集,因为扩展字符集中有其他范围的字母字符。注意,如果原始字符不是大写字符,
or al, 0x20
永远不能创建小写字符。因为这些范围相对于ASCII码的模32边界是相同地“对齐”的。安排循环结构,使条件分支位于底部。使用
jmp
进入循环以加载和测试,或者剥离第一次迭代的该部分。(Why are loops always compiled into "do...while" style (tail jump)?)使用
movzx
加载避免在写入AL时错误地依赖于将低字节合并到EAX中。如果输入在'a'之前,
sub al, 'a'
将为负符号,或者无符号将返回到高值,因此cmp al, 'z'-'a'
/ja
将拒绝它。如果输入在
'z'
之后,sub al, 'a'
将留下大于25('z'-'a'
)的值,因此无符号比较也将拒绝它。编译器在编译像
c <= 'z' && c >= 'a'
这样的C表达式时使用这种无符号比较技巧,因此您可以确保对于每个可能的输入,它的工作方式都与该表达式相同。其他款式注解:通常你只需要增加ESI,而不是同时拥有指针和索引。另外,如果你可以使用AL值(字母表中的0-25索引),你可能不需要
mov edx, eax
。制作一个副本并使用这个“破坏性”测试通常比2个单独的分支要好。NASM语法允许像C这样的字符常量,所以你可以把
0x41
写为'A'
,或者把0x7A
写为'z'
,例如cmp al, 'a'
,这样你甚至不需要注解这一行。这样写(
next_char
标签在循环的顶部)可以在底部节省一个jmp
。循环中的指令越少越好。现在编写asm的唯一目的是性能,所以如果不是太混乱的话,从一开始就学习这样的好技术是有意义的。如果没有http://agner.org/optimize/的链接,任何汇编答案都是不完整的。ascii(1)
或http://www.asciitable.com/的输出8e2ybdfx4#
这个函数接受一个字符串,并使用ascii表的值来确定它是大写字符还是小写字符。CMP--〉BLS和CMP--〉BLI指令用来确定它是大写字符还是小写字符。如果它是小写字符,后面的代码将大写字符。