1、原題再現:
輸入一個學生的身份證號碼,程序檢驗身份證號碼是否合法。並顯示省份、年齡、性別等信息。
下面是身份證號碼的規則:
身份證號碼共18位。前6位是地址碼,7–14位是出生年月日,後面4位是生成的代碼,第17位用來做性別判定: 偶數 – 女 ; 奇數— 男 。
第十八位數字的計算方法爲:
1)、 將前面的身份證號碼17位數分別乘以不同的係數。從第一位到第十七位的係數分別爲:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
2)、將這17位數字和係數相乘的結果相加。
3)、用加出來和除以11,看餘數是多少?
4)、餘數只可能有0 1 2 3 4 5 6 7 8 9 10這11個數字。其分別對應的最後一位身份證的號碼爲1 0 X 9 8 7 6 5 4 3 2。
5)、通過上面得知如果餘數是2,就會在身份證的第18位數字上出現羅馬數字的Ⅹ。如果餘數是10,身份證的最後一位號碼就是2。
2、設計思路
功能主要分爲兩個部分,一是判斷是否合法,二是輸出身份信息,包括省份,出生日期,性別,年齡。
判斷合法:包括判斷:①首兩位省份信息是否合法,即判斷是否有省份的編碼是輸入的首兩位。
②判斷出生日期是否合法。首先判斷月份數是不是合理,合理的話就判斷接下來日期是否合理:先判斷是不是二月,不在二月的話就只要判斷日期數是否在最大與最小值之間即可;是二月就需要判斷是否是閏年了:先判斷日期是否>29或者<0,是的話就不合法,不是的話再判斷是不是29,是的話,就判斷前面年份數是否是閏年,是的話就合法,否則不合法。③判斷第十八位是否合法。直接將十七位乘上係數再累加,最後除以11,根據餘數判斷尾數是否合法。④判斷長度是否合法。直接將輸入字符串的id[1],即實際輸入長度(不包括回車)與18比較即可。
輸出身份信息:輸出省份信息、出身日期、年齡、性別。
最終界面:
3、具體實現
運行環境:DOSBox,怎麼在DOSBox上運行彙編可參考:DOSBox裏運行彙編程序
部分代碼:(完整版在最後)
stack segment stack
db 200 dup(0)
stack ends
data segment
id db 20,?,20 dup('$')
info1 db 'Please input your id:$' ;提示輸入id
info2 db 'Your province is:$' ;輸出省份信息
info3 db 'The number length is incorrect!$' ;輸入身份證號碼位數不對
info4 db 'The id number is of correct length!!$' ;長度正確
info5 db 'Id card number valid!!$' ;進行多重檢查後最後提示檢查合格
info6 db 'your gender is:$' ;輸出性別
info7 db 'woman!$'
info8 db 'man!$'
info9 db 'The id number ends correctly!$' ;身份證號尾數正確
info10 db 'The last digit of the id number is incorrect!$' ;尾數不正確
info11 db 'Province information exists!$' ;省份信息存在
info12 db 'The province information does not exist!$' ;省份信息不存在
info13 db 'The current year is a leap year! Reasonable year of birth!$' ;閏年
info14 db 'The current year is not a leap year! The year of birth is not reasonable!$' ;不是閏年
info15 db 'Reasonable date of birth!$' ;出生日期合理
info16 db 'The date of birth is not reasonable!$' ;出生日期不合理
info17 db 'Congratulations, the id number entered is legal and valid!$' ;最終判斷合法且有效
info18 db 'Your identity information is:$' ;身份證信息爲
info19 db 'Your date of birth is:$' ;輸出出生日期
info20 db 'Your age is:$' ;輸出年齡
province db 11h,'BJ',12h,'TJ',13h,'HE',14h,'SX',15h,'NM'
db 21h,'LN',22h,'JN',23h,'HL',31h,'SH'
db 32h,'JS',33h,'ZJ',34h,'AH',35h,'FJ',36h,'JX'
db 37h,'SD',41h,'HA',42h,'HB',43h,'HN'
db 44h,'GD',45h,'GX',46h,'HI',50h,'CQ',51h,'SC'
db 52h,'GZ',53h,'YN',54h,'XZ',61h,'SN'
db 62h,'GS',63h,'QH',64h,'NX',65h,'XJ',71h,'TW'
db 81h,'HK',82h,'MO',91h,'FOREIGN';省份編號
coef db 7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2 ;計算第18位數字時的係數
final db 1,0,'X',9,8,7,6,5,4,3,2 ;第18位可能的取值
leapyear db 31,29,31,30,31,30,31,31,30, 31,30,31 ;閏年每月的天數
notleapyear db 31,28,31,30,31,30,31,31,30,31,30,31 ;平年每月的天數
divisors dw 10000,1000,100,10,1 ;將ax中的16進制年齡轉成十進制然後輸出
result db 0,0,0,0,0,'$' ;存放年齡
data ends
code segment
assume cs:code,ds:data,ss:stack
checkbirth MACRO ;判斷出生日期是否合法
local no
local judge
local yes
local ff
local leap
clc
push ax
push bx
push cx
push dx
push si
push di
xor ax,ax
xor bx,bx
xor cx,cx
xor dx,dx
mov al,id[12] ;獲取四位出生有效日期,不含年份
mov bl,id[13]
mov cl,id[14]
mov dl,id[15]
sub al,30h ;01h
sub bl,30h ;02h
sub cl,30h ;00h
sub dl,30h ;08h
mov di,10
mov si,dx
mul di ;dx:ax=ax*di
add ax,bx
mov bx,ax ;bx存儲月份數12=c
mov ax,cx
mul di
add ax,si ;ax裏面存儲着天數8=8
mov si,12
cmp bx,si
ja no ;月份數大於12,不合理,直接退出
mov si,0
cmp bx,si
jbe no ;月份數<=0,不合理,直接退出
jmp judge ;月份數都合理,轉向判斷日期的部分
no:display info16 ;出身日期不合理,請重新輸入
clc
stc
jmp exit
yes:display info15 ;出生日期合理
clc
jmp exit
judge:xor cx,cx ;先根據月份數找到可能的兩種日期,即平年和閏年,分別存在cx,dx裏面
xor dx,dx
mov si,bx
mov cl,leapyear[si-1] ;兩種可能的天數
mov dl,notleapyear[si-1]
cmp cl,dl
jz ff ;兩個日期數相同,就不需要判斷是否爲閏年了,只需要判斷大小月是否滿足
mov si,29 ;該月份爲2月
cmp ax,si
ja no ;大於29顯然不合理
mov si,0
cmp ax,si
jbe no ;<=0顯然也不合理,否則就要判斷是否是閏年了
mov si,29
cmp ax,si
jz leap ;日期爲29則判斷是不是閏年
jmp yes ;否則合理
leap:checkleapyear
jc yes ;返回CF=1說明是閏年,出生日期有效
jnc no
ff: cmp ax,cx ;兩個可能的天數一致,只需要判斷大小月,即只需要判斷天數是否在有有效區間內
ja no ;大於可能的最大日期,直接判斷不合理
mov si,0
cmp ax,si
jbe no ;<=0也不合理
jmp yes ;否則一定會理的
exit:pop di
pop si
pop dx
pop cx
pop bx
pop ax
ENDM
checkleapyear MACRO ;判斷是不是閏年
ENDM
checkend MACRO ;檢查第十八位是否合法
ENDM
checkgender MACRO
local woman
local man
local exit
push bx
xor bx,bx
mov bl,id[18] ;第17位,表示性別
display info6
test bl,01h ;與1進行與運算判斷奇偶
jz woman
lea dx,info8
mov ah,09h
int 21h
jmp exit
woman:lea dx,info7
mov ah,09h
int 21h
exit:pop bx
ENDM
checklength MACRO ;檢查長度是否合格
local corr
local wrong
local exit
clc
push ax
mov al,[id+1] ;id字符串的長度存在地址首位的下一位
cmp al,18
jnz wrong
corr:display info4
jmp exit
wrong:display info3
clc
stc ;cf=1表示長度不正確,繼續輸入
exit: pop ax
ENDM
checkprovince MACRO ;檢查前兩位省份信息是否正確
ENDM
display MACRO x ;輸出字符串並換行
push ax
push dx
newline
mov ah,09h
lea dx,x
int 21h
pop dx
pop ax
ENDM
dispchar MACRO x ;輸出單個字符並換行
push dx
push ax
newline
mov ah,02h
mov dl,x
int 21h
pop ax
pop dx
ENDM
dispchar2 MACRO x ;輸出單個字符不換行,用於輸出省份信息
push dx
push ax
mov ah,02h
mov dl,x
int 21h
pop ax
pop dx
ENDM
assign MACRO r1,c1,r2,c2 ;這裏犯了一個致命錯誤,就是把cx,dx壓入堆棧,導致數據初始化不成功
mov ch,r1
mov cl,c1
mov dh,r2
mov dl,c2
ENDM
cls MACRO r1,c1,r2,c2,x ;清屏並將光標置於左上角
push ax
push bx
push dx
mov ah,06h
mov al,0
mov bh,x
assign r1,c1,r2,c2 ;設置入口值
int 10h
mov ah,02h ;置光標位置
mov bh,0
mov dh,0
mov dl,0
int 10h
pop dx
pop bx
pop ax
ENDM
getprovince MACRO ;根據id獲取省份信息
ENDM
getbirth MACRO ;獲取出生日期
ENDM
getage MACRO ;獲取年齡
ENDM
newline MACRO ;回車換行
push ax
push dx
mov ah,02h
mov dl,0ah
int 21h
mov ah,02h
mov dl,0dh
int 21h
pop dx
pop ax
ENDM
main: mov ax,data ;主程序
mov ds,ax
cls 0,0,99,99,0bh
clc ;先將cf清零,下面備用
agn:newline
display info1
mov ah,0ah ;不合理則循環輸入
lea dx,id
int 21h
checkprovince ;若不合理就讓cf=1
jc agn
checklength ;同樣長度不爲18就繼續要求輸入
jc agn
checkbirth ;出生日期不合理
jc agn
checkend
jc agn
newline
display info17 ;提示有效
newline
display info18 ;開始顯示信息
mov cx,30
newline
line1:mov dl,2dh ;顯示分割線------
mov ah,02h
int 21h
loop line1
getprovince ;顯示身份信息
getbirth ;顯示出身日期
getage ;顯示年齡信息
checkgender ;顯示性別信息
newline
mov cx,30
line2:mov dl,2dh ;顯示分割線------
mov ah,02h
int 21h
loop line2
mov ah,4ch
int 21h
code ends
end main