2.3 分类统计字符个数
1.题目:分类统计字符个数
2.实验要求:
程序接收用户键入的一行字符(字符个数不超过80个,该字符串用回车符结束),并按字母,数字及其他字符分类计数,然后将结果存入以letter,digit和other为名的存储单元中。
datarea segment
letter1 db ?
digit1 db ?
other1 db ?
string label byte
max db 80
act db ?
str db 80 dup(?)
print db 13,10,'Please enter the string:','$'
mess1 db 13,10, 'The total number of letter : ','$'
mess2 db 13,10,'The total number of digit : ','$'
mess3 db 13,10,'The total number of other character : ','$'
datarea ends
prognam segment
assume cs:prognam,ds:datarea
start: push ds
sub ax,ax
push ax
mov ax,datarea
mov ds,ax
mov es,ax
mov letter1,0
mov digit1,0
mov other1,0
lea dx,print
mov ah,09h
int 21h
lea dx,string
mov ah,0ah
int 21h
sub ch,ch
mov cl,[string+1]
lea si,string+2
digitseg:
mov al,[si]
cmp al,'0'
jb otherseg ;小于0为其他,0到9为数字
cmp al,'9'
ja letter1seg
inc digit1
jmp loop1
letter1seg:
cmp al,'A' ;接上面,判断9之后,大于9,小于A为其他,A到Z为字母
jb otherseg ;jb cf=1 (无符号数溢出)则转移,ja cf与zf=1则转移
cmp al,'Z'
ja letter2seg
inc letter1
jmp loop1
letter2seg:
cmp al,'a' ;接上面,判断Z之后,大于Z,小于a为其他,a到z为字母
jb otherseg
cmp al,'z'
ja otherseg
inc letter1
jmp loop1
otherseg:
inc other1
loop1:
inc si
dec cl
cmp cl,0
jz print1
jne digitseg ;重复分类过程
print1:
lea dx,mess1
mov ah,09h
int 21h
mov al,letter1
call disp
lea dx, mess2
mov ah,09h
int 21h
mov al,digit1
call disp
lea dx, mess3
mov ah,09h
int 21h
mov al,other1
call disp
exit:
mov ah, 4ch
int 21h
disp: ;十进制数形式显示AL中的内容.
mov ah, 0
mov bl, 10
div bl ;div 无符号:div src 16位操作:商ax=(dx,ax)/src,余数dx
add al, 30h ;比如说al=15h,即21,表示letter数量,然后,这个过程就是,ax=0015h(21),除以bl,bl值为10
mov dl, al ;则除完了的结果为2余1,则ah=01,al=02,即ax=0102h;,那么al+30h即为表示该数字的ASCII码值,因为0的ASCII值为30h
mov bh, ah ;则ax=0132h,dl=32,bh=01;
mov ah, 02h ;显示输出dx,则显示32码对应的数字,2
int 21h
mov al, bh ;把01给al,然后算出ASCII码,然后给dx,然后显示
add al, 30h
mov dl, al ;除数B有 8位和16位两种,保存在一个reg寄存器里 或是内存单元中。
;被除数A 默认存放在AX中(16位以内) 或 AX和DX中(32位,DX存放高16位,AX存放低16位)
;结果: 如果除数B是8位,那么除法的结果AL保存商,AH保存余数,
;如果除数B是16位,那么除法的结果 AX保存商,DX保存余数。
mov ah, 02h
int 21h
ret
;---------------------------------------
;****************************************
prognam ends
end start
运行结果:
(1)这个实验我做了额外的16进制数转换成10进制数输出,在不进入debug运行的情况下,显示出的结果更加规范美观。
修改前,16进制输出:
修改之后,10进制输出:
(2)在debug运行结果:
反汇编结束后,我们利用g0b命令跳到程序执行前,然后利用d0命令显示寄存器内容,其中蓝色标记代表存入letter,digit,other的字符数量,接着红色的标记代表为输入字符申请的空间,最多80个字符(16进制为50),接着黄色标记代表输入的字符总数,紫色的标记代表存入的80个字符,显示为对应字符的ASCII码,后续即为程序的输出显示语句之类的其他ASCII码。
利用g9b命令跳到程序输入字符,显示的阶段,然后利用d0命令显示寄存器内容,输入字符之后,统计字符结果保存到相应位置,我们可以清晰的看到执行的结果。其中输出是用10进制表示,而存的时候显示为16进制,我输入字符之后,letter有16个,对应第一个位置存16进制10,digit有9个,对应显示16进制09,other有10个,对应显示16进制0a;黄色标记部分显示字符总数35,16进制显示23,接着紫色部分显示的是输入字符的ASCII码。
问题及收获
本次实验自己动手做实验教材2.3,刚开始看到题目感觉利用上一次做的实验的思想就可以实现,如何输入,如何将其保存,然后再一个个字符拿出来比较属于哪一类,然后将该类别数量增一。可以利用分支程序实现。最后我采用16进制转换成10进制输出结果,这样更加直观。总体来说,遇到的问题没有很多,其他一些小问题,稍微注意一点就可以了。就是我想着要将其转换为10进制数字显示时,有点麻烦,我找了好多资料,然后对比分析,最后自己写出了相应的转换代码:
最开始就是卡在div这个操作这里,因为我以为无论操作数有多少位,余数都存在dx中了,然而如果除数是8位,那么除法的结果AL保存商,AH保存余数,如果除数是16位,除法的结果才是 AX保存商,DX保存余数。这样搞明白之后,把相应的数字转换成ASCII码,以字符形式分高位,地位输出。