标题:身份证号编码规则及函数写法

-------------------------------------------------------------------------------------------------------------------------------

时间:2009/1/12 12:50:55

-------------------------------------------------------------------------------------------------------------------------------

内容:

关于身份证的几个函数
出处:网络


*身份证号出错信息(对字段:sfzherrc的编码解释)
*1、"身份证号不满15位!"2、性别与身份证不符3、出生月份出错(不在1-12范围内)4、出生日期出错(不在1-31范围内)5、18位校验位出错(sfzherrc中紧跟括号内的内容为正确的第18位校验码)6、18位身份证出生年份出错(不是19)
*检查原则:不满15位只检查位数,15位检查出生年、月、日的超界关系、性别对应关系(男:身份证第15位为13579,女:身份证第15位为02468)
*检查原则:18位身份证除检查15位的检查原则外增加检查最后一位检验码的关系校验

以下附身份证号的算法函数,可供大家参考!!

*身份号码第18位校验位的算法〖中华人民共和国国家标准 GB 11643-1999〗(依此算法写的函数存放在过*程文件myproc.prg中<附后>)
* 15位的身份证编码首先把出生年扩展为4位,简单的就是增加一个19,但对于1900前年出生的人不适用
* ∑(ai×Wi)(mod 11)……………………………………(1)
* 公式(1)中:
* i----表示号码字符从由至左包括校验码在内的位置序号;
* ai----表示第i位置上的号码字符值;
* Wi----示第i位置上的加权因子,其数值依据公式Wi=2^(n-1)(mod 11)计算得出((n-1)为幂)。
* i 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
* ai 3 4 0 5 2 4 1 9 8 0 0 1 0 1 0 0 1 a1
* Wi 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 1
* ai×Wi 21 36 0 25 16 16 2 9 48 0 0 9 0 5 0 0 2 a1
* 根据公式(1)进行计算:
* ∑(ai×Wi) =(21+36+0+25+16+16+2+9+48++0+0+9+0+5+0+0+2) = 189
* 189 ÷ 11 = 17 + 2/11
* ∑(ai×Wi)(mod 11) = 2
* 然后根据计算的结果,从下面的表中查出相应的校验码,其中X表示计算结果为10:
* ∑(ai×WI)(mod 11) 0 1 2 3 4 5 6 7 8 9 10
* 校验码字符值ai 1 0 X 9 8 7 6 5 4 3 2
以下为过程文件myproc.prg的内容
*身份证升位程序
*作者:窦学田
*功能:计算身份证的校验码
*入口参数:15位号码 或17位号码
*返回:18位身份证号码

Function NewIdCode()
Parameters OldId
Local id1,id2,i,NewId
id1=Strtran(OldId,' ','')
id2=0
If Len(id1)=15
id1=Left(OldId,6)+'19'+Right(OldId,9)
Endif
If Len(id1)=17
For i=1 to 17
id2=id2+Val(Substr(id1,18-i,1))*(Mod(2^i,11))
EndF
id1=id1+Iif(Mod(1-id2,11)=10,'X',Str(Mod(1-id2,11),1))
Endif
NewId=id1
Return NewId

*测试18位的身份证是否正确
*作者:窦学田
*功能:测试18位身份证的校验码
*入口参数:18位号码
*返回:出错信息
FUNCTION GetOld()
PARAMETERS sID
s1=' 7 910 5 8 4 2 1 6 3 7 910 5 8 4 2'
s2='10X98765432'
sID=UPPER(ALLTRIM(sID))
IF LEN(sId)=15
sId=STUFF(sId,7,0,"19")
ENDIF
NewId=LEFT(sID,17)
jym=0
FOR i=1 TO 17
jym=jym+val(subs(s1,i*2-1,2))*val(subs(NewId,i,1))
ENDFOR
NewId= NewId+ SUBSTR(s2,MOD(jym,11)+1,1)
IF LEN(sId)=18
IF RIGHT(sId,1)<>RIGHT(Newid,1) &&正确
MESSAGEBOX(sid+"为错误身份证号码!",48,"警告")
ENDIF
ENDIF

*测试身份证的年月日的合法性YMDS(year,month,date,sex)
*作者:窦学田
*功能:测试18位身份证的年月日的合法性
*入口参数:原表中的性别代码,原身份证号码
*返回:综合出错信息

FUNCTION CheckYMDS()
PARAMETERS F_xbdm,F_ID
Local rtn_errcode
rtn_errcode=''
sfxb=iif(F_xbdm='1','13579','02468')
if len(allt(F_ID))=15

sfsex=subs(F_ID,15,1)
if !sfsex$sfxb &&测试性别
rtn_errcode=IIF(empty(rtn_errcode),"2",allt(rtn_errcode)+'+2')
endif
sfy=subs(F_ID,9,2) &&月
sfr=subs(F_ID,11,2) &&日

if !(val(sfy)<=12)
rtn_errcode=IIF(empty(rtn_errcode),"3",allt(rtn_errcode)+'+3')
endif

if !(val(sfr)<=31)
rtn_errcode=IIF(empty(rtn_errcode),"4",allt(rtn_errcode)+'+4')
endif

else
sfsex=subs(F_ID,17,1)
if !sfsex$sfxb &&测试性别
rtn_errcode=IIF(empty(rtn_errcode),"2",allt(rtn_errcode)+'+2')
endif

sfy=subs(F_ID,11,2) &&月
sfr=subs(F_ID,13,2) &&日

if !(val(sfy)<=12) &&月
rtn_errcode=IIF(empty(rtn_errcode),"3",allt(rtn_errcode)+'+3')
endif

if !(val(sfr)<=31) &&日
rtn_errcode=IIF(empty(rtn_errcode),"4",allt(rtn_errcode)+'+4')
endif

*以下测试第18位校验码的正确性
s1=' 7 910 5 8 4 2 1 6 3 7 910 5 8 4 2'
s2='10X98765432'
F_ID=UPPER(ALLTRIM(F_ID))
IF LEN(F_Id)=15
F_Id=STUFF(F_Id,7,0,"19")
ENDIF
NewId=LEFT(F_ID,17)
jym=0
FOR i=1 TO 17
jym=jym+val(subs(s1,i*2-1,2))*val(subs(NewId,i,1))
ENDFOR
NewId= NewId+ SUBSTR(s2,MOD(jym,11)+1,1)
IF LEN(F_Id)=18
IF RIGHT(F_Id,1)<>RIGHT(Newid,1) &&不正确
rtn_errcode=IIF(empty(rtn_errcode),"5"+'(应为'+RIGHT(Newid,1)+')',allt(rtn_errcode)+'+5'+'(应为'+RIGHT(Newid,1)+')') &&返回出错信息及正确的第18位校验码
ENDIF
ENDIF

if subs(F_ID,7,2)<>'19' &&测试年(19)
rtn_errcode=IIF(empty(rtn_errcode),"6",allt(rtn_errcode)+'+6')
endif
endif
return rtn_errcode

关于身份证的几个函数
出处:网络


*身份证号出错信息(对字段:sfzherrc的编码解释)
*1、"身份证号不满15位!"2、性别与身份证不符3、出生月份出错(不在1-12范围内)4、出生日期出错(不在1-31范围内)5、18位校验位出错(sfzherrc中紧跟括号内的内容为正确的第18位校验码)6、18位身份证出生年份出错(不是19)
*检查原则:不满15位只检查位数,15位检查出生年、月、日的超界关系、性别对应关系(男:身份证第15位为13579,女:身份证第15位为02468)
*检查原则:18位身份证除检查15位的检查原则外增加检查最后一位检验码的关系校验

以下附身份证号的算法函数,可供大家参考!!

*身份号码第18位校验位的算法〖中华人民共和国国家标准 GB 11643-1999〗(依此算法写的函数存放在过*程文件myproc.prg中<附后>)
* 15位的身份证编码首先把出生年扩展为4位,简单的就是增加一个19,但对于1900前年出生的人不适用
* ∑(ai×Wi)(mod 11)……………………………………(1)
* 公式(1)中:
* i----表示号码字符从由至左包括校验码在内的位置序号;
* ai----表示第i位置上的号码字符值;
* Wi----示第i位置上的加权因子,其数值依据公式Wi=2^(n-1)(mod 11)计算得出((n-1)为幂)。
* i 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
* ai 3 4 0 5 2 4 1 9 8 0 0 1 0 1 0 0 1 a1
* Wi 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 1
* ai×Wi 21 36 0 25 16 16 2 9 48 0 0 9 0 5 0 0 2 a1
* 根据公式(1)进行计算:
* ∑(ai×Wi) =(21+36+0+25+16+16+2+9+48++0+0+9+0+5+0+0+2) = 189
* 189 ÷ 11 = 17 + 2/11
* ∑(ai×Wi)(mod 11) = 2
* 然后根据计算的结果,从下面的表中查出相应的校验码,其中X表示计算结果为10:
* ∑(ai×WI)(mod 11) 0 1 2 3 4 5 6 7 8 9 10
* 校验码字符值ai 1 0 X 9 8 7 6 5 4 3 2
以下为过程文件myproc.prg的内容
*身份证升位程序
*作者:窦学田
*功能:计算身份证的校验码
*入口参数:15位号码 或17位号码
*返回:18位身份证号码

Function NewIdCode()
Parameters OldId
Local id1,id2,i,NewId
id1=Strtran(OldId,' ','')
id2=0
If Len(id1)=15
id1=Left(OldId,6)+'19'+Right(OldId,9)
Endif
If Len(id1)=17
For i=1 to 17
id2=id2+Val(Substr(id1,18-i,1))*(Mod(2^i,11))
EndF
id1=id1+Iif(Mod(1-id2,11)=10,'X',Str(Mod(1-id2,11),1))
Endif
NewId=id1
Return NewId

*测试18位的身份证是否正确
*作者:窦学田
*功能:测试18位身份证的校验码
*入口参数:18位号码
*返回:出错信息
FUNCTION GetOld()
PARAMETERS sID
s1=' 7 910 5 8 4 2 1 6 3 7 910 5 8 4 2'
s2='10X98765432'
sID=UPPER(ALLTRIM(sID))
IF LEN(sId)=15
sId=STUFF(sId,7,0,"19")
ENDIF
NewId=LEFT(sID,17)
jym=0
FOR i=1 TO 17
jym=jym+val(subs(s1,i*2-1,2))*val(subs(NewId,i,1))
ENDFOR
NewId= NewId+ SUBSTR(s2,MOD(jym,11)+1,1)
IF LEN(sId)=18
IF RIGHT(sId,1)<>RIGHT(Newid,1) &&正确
MESSAGEBOX(sid+"为错误身份证号码!",48,"警告")
ENDIF
ENDIF

*测试身份证的年月日的合法性YMDS(year,month,date,sex)
*作者:窦学田
*功能:测试18位身份证的年月日的合法性
*入口参数:原表中的性别代码,原身份证号码
*返回:综合出错信息

FUNCTION CheckYMDS()
PARAMETERS F_xbdm,F_ID
Local rtn_errcode
rtn_errcode=''
sfxb=iif(F_xbdm='1','13579','02468')
if len(allt(F_ID))=15

sfsex=subs(F_ID,15,1)
if !sfsex$sfxb &&测试性别
rtn_errcode=IIF(empty(rtn_errcode),"2",allt(rtn_errcode)+'+2')
endif
sfy=subs(F_ID,9,2) &&月
sfr=subs(F_ID,11,2) &&日

if !(val(sfy)<=12)
rtn_errcode=IIF(empty(rtn_errcode),"3",allt(rtn_errcode)+'+3')
endif

if !(val(sfr)<=31)
rtn_errcode=IIF(empty(rtn_errcode),"4",allt(rtn_errcode)+'+4')
endif

else
sfsex=subs(F_ID,17,1)
if !sfsex$sfxb &&测试性别
rtn_errcode=IIF(empty(rtn_errcode),"2",allt(rtn_errcode)+'+2')
endif

sfy=subs(F_ID,11,2) &&月
sfr=subs(F_ID,13,2) &&日

if !(val(sfy)<=12) &&月
rtn_errcode=IIF(empty(rtn_errcode),"3",allt(rtn_errcode)+'+3')
endif

if !(val(sfr)<=31) &&日
rtn_errcode=IIF(empty(rtn_errcode),"4",allt(rtn_errcode)+'+4')
endif

*以下测试第18位校验码的正确性
s1=' 7 910 5 8 4 2 1 6 3 7 910 5 8 4 2'
s2='10X98765432'
F_ID=UPPER(ALLTRIM(F_ID))
IF LEN(F_Id)=15
F_Id=STUFF(F_Id,7,0,"19")
ENDIF
NewId=LEFT(F_ID,17)
jym=0
FOR i=1 TO 17
jym=jym+val(subs(s1,i*2-1,2))*val(subs(NewId,i,1))
ENDFOR
NewId= NewId+ SUBSTR(s2,MOD(jym,11)+1,1)
IF LEN(F_Id)=18
IF RIGHT(F_Id,1)<>RIGHT(Newid,1) &&不正确
rtn_errcode=IIF(empty(rtn_errcode),"5"+'(应为'+RIGHT(Newid,1)+')',allt(rtn_errcode)+'+5'+'(应为'+RIGHT(Newid,1)+')') &&返回出错信息及正确的第18位校验码
ENDIF
ENDIF

if subs(F_ID,7,2)<>'19' &&测试年(19)
rtn_errcode=IIF(empty(rtn_errcode),"6",allt(rtn_errcode)+'+6')
endif
endif
return rtn_errcode