zoukankan      html  css  js  c++  java
  • 身份证号码最后一位校检码的计算公式

    我国现行使用公民身份证号码有两种尊循两个国家标准,〖GB 11643-1989〗和〖GB 11643-1999〗。
    〖GB 11643-1989〗中规定的是15位身份证号码:排列顺序从左至右依次为:六位数字地址码,六位数字出生日期码,三位数字顺序码,其中出生日期码不包含世纪数。
    〖GB 11643-1999〗中规定的是18位身份证号码:公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。
    地址码表示编码对象常住户口所在县(市、旗、区)的行政区划代码。
    生日期码表示编码对象出生的年、月、日,其中年份用四位数字表示,年、月、日之间不用分隔符。
    顺序码表示同一地址码所标识的区域范围内,对同年、月、日出生的人员编定的顺序号。
    顺序码的奇数分给男性,偶数分给女性。
    校验码是根据前面十七位数字码,按照ISO 7064:1983.MOD 11-2校验码计算出来的检验码。
    为什么除11,在于计算校验码时的函数。请看下边的函数:
    公式如下:
      ∑(a[i]*W[i]) mod 11 ( i = 2, 3, ..., 18 ) (1)
      "*" 表示乘号
      i--------表示身份证号码每一位的序号,从右至左,最左侧为18,最右侧为1。
      a[i]-----表示身份证号码第 i 位上的号码
      W[i]-----表示第 i 位上的权值 W[i] = 2^(i-1) mod 11
      计算公式 (1) 令结果为 R
    根据下表找出 R 对应的校验码即为要求身份证号码的校验码C。
      R 0 1 2 3 4 5 6 7 8 9 10
      C 1 0 X 9 8 7 6 5 4 3 2
    由此看出 X 就是 10,罗马数字中的 10 就是X,所以在新标准的身份证号码中可能含有非数字的字母X。
    ~(重点看清楚)~  这个函数展开就是:
    a[1]*W[1]+a[2]*W[2]+……+a[18]*W[18]=? 
    ?mod11=“?对11求模” 
    如:22mod11=2 23mod22也是2 33mod11=3 
    就是出于后面那个数,只取商不取余数
    所以从函数和其展开式来看要对11求模,所一要除11
    以下为列子:
    *此函数功能:输入的15位或17位或18位的身份证号,返回校验后的最后一位
    *
    *-----------------------------
    FUNCTION sfzjy
    Parameters cID
    DO CASE
    CASE LEN(ALLTRIM(cID)) = 15
    cID = STUFF(ALLTRIM(cID),7,0,"19")
    CASE LEN(ALLTRIM(cID)) = 18 OR LEN(ALLTRIM(cID)) = 17
    cID =LEFT(ALLTRIM(cID),17)
    OTHERWISE
    RETURN .F.
    ENDCASE
    If Len(ALLTRIM(cID))#17
    Return .f.
    Endif
    nSum=Val(SubStr(cID,1,1)) * 7 ;
    + Val(SubStr(cID,2,1)) * 9 ;
    + Val(SubStr(cID,3,1)) * 10 ;
    + Val(SubStr(cID,4,1)) * 5 ;
    + Val(SubStr(cID,5,1)) * 8 ;
    + Val(SubStr(cID,6,1)) * 4 ;
    + Val(SubStr(cID,7,1)) * 2 ;
    + Val(SubStr(cID,8,1)) * 1 ;
    + Val(SubStr(cID,9,1)) * 6 ;
    + Val(SubStr(cID,10,1)) * 3 ;
    + Val(SubStr(cID,11,1)) * 7 ;
    + Val(SubStr(cID,12,1)) * 9 ;
    + Val(SubStr(cID,13,1)) * 10 ;
    + Val(SubStr(cID,14,1)) * 5 ;
    + Val(SubStr(cID,15,1)) * 8 ;
    + Val(SubStr(cID,16,1)) * 4 ;
    + Val(SubStr(cID,17,1)) * 2
    *计算校验位
    check_number=INT((12-nSum % 11)%11)
    If check_number=10
    check_number='X'
    Endif
    Return check_number
    Endfunc
    *-----------------------------
    *
    *此函数功能:输入的15位或18位身份证号,返回正确的18位的身份证号。
    *
    *---------------------------
    FUNCTION IDCardTF
    PARAMETERS cNumber
    #DEFINE InvalidSize "身份证号码长度不正确!"
    #DEFINE InvalidChar "身份证号码包括非法字符!"
    #DEFINE InvalidDate "出生日期无效!"
    #DEFINE InvalidReturnValue ".F."
    PRIVATE cString
    DO CASE
    CASE LEN(cNumber) = 15
    cString = STUFF(cNumber,7,0,"19")
    CASE LEN(cNumber) = 18
    cString =LEFT(ALLTRIM(cNumber),17)
    OTHERWISE
    MESSAGEBOX(InvalidSize,48,"信息提示")
    RETURN InvalidReturnValue
    ENDCASE
    PRIVATE i,n,iRet
    STORE 0 TO iRet
    FOR i = 1 TO 17
    n = SUBSTR(cString,i,1)
    IF NOT ISDIGIT(n)
    MESSAGEBOX(invalidChar,48,"信息提示")
    RETURN invalidReturnValue
    ENDIF
    n = 2 ^ (18 - i) % 11 * VAL(n)
    iRet = iRet + n
    ENDFOR
    iRet = iRet % 11 + 1
    PRIVATE oldDateSet, oldCentury
    PRIVATE oldStrictDate, BirthDay
    oldDateSet = SET("DATE")
    oldCentury = SET("CENTURY")
    oldStrictDate = SET("STRICTDATE")
    SET DATE ANSI
    SET CENTURY ON
    SET STRICTDATE TO 0
    BirthDay = CTOD(SUBSTR(cString,7,4)+"-"+SUBSTR(cString,11,2)+"-"+SUBSTR(cString,13,2))
    SET STRICTDATE TO &oldStrictDate
    SET CENTURY &oldCentury
    SET DATE &oldDateSet
    IF EMPTY(BirthDay)
    MESSAGEBOX(InvalidDate,48,"信息提示")
    RETURN InvalidReturnValue
    ENDIF
    RETURN cString+SUBSTR("10x98765432",iRet,1)
    ENDFUNC
    *-----------------------------
    *
    *此函数功能:检验输入的15位或18位身份证号码是否为合法
    *
    *-----------------------------
    FUNCTION sfzyn
    LPARAMETERS lstr &&参数:lstr 传入的号码
    LOCAL lstr,relyn,tsfz
    LOCAL m1,m2,m3,m4,m,i,r,c,ai,wi
    SET TALK OFF
    SET DATE TO ANSI
    SET CENT ON
    relyn=.F. &&返回值
    tsfz=ALLT(lstr)
    *分别用m1,m2,m3,m4表示四个条件是否成立
    STOR .T. TO m1,m2,m3,m4
    *条件1:只能是15或18位
    m1=IIF(LEN(tsfz)=15 OR LEN(tsfz)=18,.T.,.F.)
    IF LEN(tsfz)=15 && 15位的号码
    FOR i=1 TO 15 &&检查每一位是否为数字
    m=ASC(SUBS(tsfz,i,1))
    IF m<48 OR m>57 &&数字
    m2=.F. &&若有一位不是就不再查
    EXIT
    ENDIF
    ENDFOR
    m="19" +SUBS(tsfz, 7,2) &&早期的号都是上个世纪的
    m=m+"."+SUBS(tsfz, 9,2)
    m=m+"."+SUBS(tsfz,11,2)
    m=CTOD(m)
    IF ISNULL(m) OR isblank(m)
    m3=.F. &&生日不正确
    ENDIF
    ENDIF
    IF LEN(tsfz)=18 && 18位的号码
    FOR i=1 TO 17
    m=ASC(SUBS(tsfz,i,1))
    IF m<48 OR m>57
    m2=.F.
    EXIT
    ENDIF
    ENDFOR
    m=SUBS(tsfz,7,4)
    m=m+"."+SUBS(tsfz,11,2)
    m=m+"."+SUBS(tsfz,13,2)
    m=CTOD(m)
    IF ISNULL(m) OR isblank(m)
    m3=.F.
    ENDIF
    r=0 &&计算校验位
    FOR i=18 TO 2 STEP -1
    ai=VAL(SUBS(tsfz,19-i,1))
    wi=MOD(2^(i-1),11)
    r=r+ai*wi
    NEXT
    r=MOD(r,11)
    DO CASE
    CASE r=0
    c="1"
    CASE r=1
    c="0"
    CASE r=2
    c="X"
    OTHER
    c=ALLTRIM(STR(12-r))
    ENDCASE
    IF UPPE(SUBS(tsfz,18,1))<>c
    m4=.F. &&校验位与原码最末位不同
    ENDIF
    ENDIF
    *四个条件全成立,则返回.t.
    relyn=IIF(m1 AND m2 AND m3 AND m4,.T.,.F.)
    RETU relyn
    ENDFUN
    *-----------------------------
    *
    *此函数功能:输入15位或18位的身份证号,返回被校验后的18位的身份证号,若身份证号非法,则返回空
    *
    *-----------------------------
    FUNC sfjy
    PARA msfz
    ON ERRO RETU ''
    DIME T(17)
    PRIV msfz,T,sn,i
    msfz=ALLT(msfz)
    DO CASE
    CASE LEN(msfz)=15
    msfz=LEFT(msfz,6)+'19'+SUBS(msfz,7)
    CASE LEN(msfz)=18
    msfz=LEFT(msfz,17)
    OTHE
    RETU ''
    ENDC
    FOR i=1 TO 17
    IF !ISDI(SUBS(msfz,i,1))
    RETU ''
    ENDI
    ENDF
    IF !LEFT(msfz,2)$'11,12,13,14,15,21,22,23,31,32,33,34,35,36,37,41,42,43,44,45,46,50,51,52,53,54,61,62,63,64,65,71,81,82'
    RETU ''
    ENDI
    IF EMPT(DATE(VAL(SUBS(msfz,7,4)),VAL(SUBS(msfz,11,2)),VAL(SUBS(msfz,13,2))))
    RETU ''
    ENDI
    sn=0
    T(1)=7
    T(2)=9
    T(3)=10
    T(4)=5
    T(5)=8
    T(6)=4
    T(7)=2
    T(8)=1
    T(9)=6
    T(10)=3
    T(11)=7
    T(12)=9
    T(13)=10
    T(14)=5
    T(15)=8
    T(16)=4
    T(17)=2
    FOR i=1 TO 17
    sn=sn+VAL(SUBS(msfz,i,1))*T(i)
    ENDF
    sn=MOD(sn,11)
    ON ERRO
    RETU msfz+SUBS('10X98765432',sn+1,1)
  • 相关阅读:
    HDU 1010 Tempter of the Bone
    HDU 4421 Bit Magic(奇葩式解法)
    HDU 2614 Beat 深搜DFS
    HDU 1495 非常可乐 BFS 搜索
    Road to Cinema
    Sea Battle
    Interview with Oleg
    Spotlights
    Substring
    Dominating Patterns
  • 原文地址:https://www.cnblogs.com/top5/p/2234849.html
Copyright © 2011-2022 走看看