【关于身份证号码】

时间:2021-11-19 20:39:23
关于身份证号码最后一位的校验码的算法如下:

我国现行使用公民身份证号码有两种尊循两个国家标准,〖GB 11643-1989〗和〖GB 11643-1999〗。
〖GB 11643-1989〗中规定的是15位身份证号码:排列顺序从左至右依次为:六位数字地址码,六位数字出生日期码,三位数字顺序码,其中出生日期码不包含世纪数。
〖GB 11643-1999〗中规定的是18位身份证号码:公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。
地址码表示编码对象常住户口所在县(市、旗、区)的行政区划代码。
生日期码表示编码对象出生的年、月、日,其中年份用四位数字表示,年、月、日之间不用分隔符。
顺序码表示同一地址码所标识的区域范围内,对同年、月、日出生的人员编定的顺序号。顺序码的奇数分给男性,偶数分给女性。
校验码是根据前面十七位数字码,按照ISO 7064:1983.MOD 11-2校验码计算出来的检验码。
公式如下:
  ∑(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。

以下为列子
*-----------------------------
*
*此函数功能:输入的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

2 个解决方案

#1


*-----------------------------
*
*此函数功能:输入的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)

#2


烦请版主把此帖整理为<精华帖>

#1


*-----------------------------
*
*此函数功能:输入的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)

#2


烦请版主把此帖整理为<精华帖>