*  回文 (C)Copyright 2006-2006 By Tiger5392
*  用法
*      ?回文(cExpress)
*  参数
*      cExpress: 字符型常量、变量、函数、表达式
*  返回值
*      一个数值
*      数值    含义
*         0    是一个空串
*         1    是单字节回文,是双字节回文
*         2    是单字节回文,不是双字节回文
*         3    不是单字节回文,是双字节回文
*         4    不是单字节回文,不是双字节回文
*  有关概念
*      单字节回文:一个字符串,一个字节一个字节地正念与倒念都一样。
*      双字节回文:一个字符串,两个字节两个字节地正念与倒念都一样。
PARAMETERS cOldString
PRIVATE cOldString,cNewString1,cNewString2,nCnt,nFlags1,nFlags2
IF EMPTY(cOldString)
  RETURN 0
ENDIF
STORE [] TO cNewString1,cNewString2
*判断是否为单字节回文
FOR nCnt=LEN(cOldString) TO 1 STEP -1
  cNewString1=cNewString1+SUBSTR(cOldString,nCnt,1)
ENDFOR
nFlags1=IIF(cOldString=cNewString1,1,3)
*判断是否为双字节回文
FOR nCnt=LEN(cOldString) TO 1 STEP -2
  cNewString2=cNewString2+SUBSTR(cOldString,nCnt-1,2)
ENDFOR
nFlags2=IIF(cOldString=cNewString2,0,1)
RETURN nFlags1+nFlags2

我国现行使用公民身份证号码有两种尊循两个国家标准,〖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(“10×98765432”,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)