大小写字母的ASCII码之间的规律,不用相差32来讲
-----------------------------2021.3.15更新-----------------------------------------
突然想到,其实小写字母第5位是1,大写字母第5位是0,也就是意味着相差32,不过前者是因,后者是果。我们习惯了十进制,一眼望去就先望到了果,要是我们是二进制世界,那应该一看就看到了因
-----------------------------2021.3.15更新-----------------------------------------
来源于王爽老师的 汇编语言
. .......... .... ..... .... ...... .. .... ...... ......
问题描述
我们要把字符串里面的小写字母变成大写字母,刚开始想着大小写字母的ASCII码相差32(20h)那么我们只要把小写字母的ASCII码值减32(20h)不久好了,但是,这绕不开一件事,就是判断一个字母是大写还是小写,但我们汇编还没学到判断逻辑的实现那么要从新想办法。
我们应该重新观察,寻找新的规律。可以看出,就ASCII码的二进制形式来看,除第5位(位数从0开始计算)外,大写字母和小写字母的其他各位都一样。大写字母ASCII码的第5位为0,小写字母的第5位为1。这样,我们就有了新的方法,一个字母,不管它原来是大写还是小写,将它的第5位置0,它就必将变为大写字母;将它的第5位置1,它就必将变为小写字母。在这个方法中,我们不需要在处理前判断字母的大小写。比如:
对于“BaSiC”中的“B”,按要求,它已经是大写字母了,不应进行改变,将它的第5位设为0,它还是大写字母,因为它的第5位本来就是0。
用什么方法将一个数据中的某一位置0还是置1?当然是用我们刚刚学过的or和and指令。
完整的汇编代码如下
assume cs:codesg,ds:datasg
datasg segment
db'BaSiC'
db 'iNfOrMaTion'
datasg ends
codesg segment
start:mov ax,datasg
mov ds,ax ;设置ds 指向 datasg段
mov bx,0 ;设置(bx)=0,ds:bx指向'Basic'的第一个字母
mov cx,5 ;设置循环次数5,因为Basic1有5个字母
s:mov al,[bx] ;将ASCII码从ds:bx所指向的单元中取出
and.al,11011111B ;将a1中的ASCII码的第5位置为0,变为大写字母
mov[bx],al ;将转变后的ASCII码写回原单元
inc bx ;(bx)加1,ds:bx指向下一个字母
loop s
mov bx,5 ;设置(bx)=5,ds:bx指向iNfOrMaTion’的第一个字母
mov cx,11 ;设置循环次数11,因为’iNfOrMaTion'有11个字母s0:
s0:mov al,[bx]
or al,00100000B ;将a1中的ASCII码的第5位置为1,变为小写字母
mov[bx],al
inc bx
loop s0
mov ax,4c00h
int 21h
codesg ends
end start
由于ASCII码表中的字符最高位都是0,所以和11011111B
做与运算和 01011111B
做与运算结果都是一样的,也就是说我们只要和01011111B
(下划线 '_'
)做与运算,就可以实现大写字母变小写字母
同理,小写变大写也是一样,我们只要和00100000B
(空格 ' '
)做与运算,就可以实现小写字母变大写字母
再引申,也就得出了大变小,小变大的方法 ———— 异或 ,只要第五位反转就是大变小,小变大,要想反转,那就和 0 异或,所以就有只要和00100000B
(空格 ' '
)做异或运算,就可以实现大变小,小变大。