您的位置:首页 > 数据库 > Oracle

oracle验证公民身份号码

2009-09-03 16:50 357 查看
首先看一下《公民身份号码》中做了明确的规定:
18位***标准在国家质量技术监督局于1999年7月1日实施的GB11643-1999《公民身份号码》中做了明确的规定。 GB11643-1999《公民身份号码》为GB11643-1989《社会保障号码》的修订版,其中指出将原标准名称"社会保障号码"更名为"公民身份号码",另外GB11643-1999《公民身份号码》从实施之日起代替GB11643-1989。GB11643-1999《公民身份号码》主要内容如下:
一、范围
该标准规定了公民身份号码的编码对象、号码的结构和表现形式,使每个编码对象获得一个唯一的、不变的法定号码。
二、编码对象
公民身份号码的编码对象是具有中华人民共和国国籍的公民。
三、号码的结构和表示形式
1、号码的结构
公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。
2、地址码
表示编码对象常住户口所在县(市、旗、区)的行政区划代码,按GB/T2260的规定执行。
3、出生日期码
表示编码对象出生的年、月、日,按GB/T7408的规定执行,年、月、日代码之间不用分隔符。
4、顺序码
表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配给女性。
5、校验码
(1)十七位数字本体码加权求和公式
S = Sum(Ai * Wi), i = 0, ... , 16 ,先对前17位数字的权求和
Ai:表示第i位置上的***号码数字值
Wi:表示第i位置上的加权因子
Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2

(2)计算模
Y = mod(S, 11)

(3)通过模得到对应的校验码
Y: 0 1 2 3 4 5 6 7 8 9 10
校验码: 1 0 X 9 8 7 6 5 4 3 2
四、举例如下:
北京市朝阳区: 11010519491231002X
广东省汕头市: 440524188001010014

再看一下***的含义:

'15位***号码含义:
'----------------------------------------
'113343 450321 432(***号:只作假设,可能此号并不存在,请勿对号入座)
'前6位 中间6位 后三位
'地区代码 生日:年月日 奇为男,偶为女
'----------------------------------------
'其中:
'各省市地区国家代码前两位代码是:
'----------------------------------
'北京 11 吉林 22 福建 35 广东 44 云南 53 天津 12 黑龙江 23 江西 36 广西 45 西藏 54 河北 13 上海 31
'山东 37 海南 46 陕西 61 山西 14 江苏 32 河南 41 重庆 50 甘肃 62 内蒙古 15 浙江 33 湖北 42
'四川 51 青海 63 辽宁 21 安徽 34 湖南 43 贵州 52 宁夏 64 新疆 65 台湾 71 香港 81 澳门 82 国外 91

'18位***号:
'---------------------------------------------------
'113343 1945 03 21 432 9(***号:只作假设,可能此号并不存在,请勿对号入座)
'前6位 四位 两位 两位 三位 一位
'地区代码 年份 月份 生日 奇为男,偶为女 检验位
'---------------------------------------------------
'其他不详。
参考资料:http://hsdwf.vicp.net/Content,2005,9,9,101.aspx

###############################################################
15位升18的方法
###############################################################

根据〖中华人民共和国国家标准 GB 11643-1999〗中有关公民身份号码的规定,公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。

地址码表示编码对象常住户口所在县(市、旗、区)的行政区划代码。生日期码表示编码对象出生的年、月、日,其中年份用四位数字表示,年、月、日之间不用分隔符。顺序码表示同一地址码所标识的区域范围内,对同年、月、日出生的人员编定的顺序号。顺序码的奇数分给男性,偶数分给女性。校验码是根据前面十七位数字码,按照ISO 7064:1983.MOD 11-2校验码计算出来的检验码。下面举例说明该计算方法。

15位的***编码首先把出生年扩展为4位,简单的就是增加一个19,但是这对于1900年出生的人不使用(这样的寿星不多了)

某男性公民身份号码本体码为34052419800101001,首先按照公式⑴计算:

∑(ai×Wi)(mod 11)……………………………………(1)

公式(1)中:
i----表示号码字符从由至左包括校验码在内的位置序号;
ai----表示第i位置上的号码字符值;
Wi----示第i位置上的加权因子,其数值依据公式Wi=2(n-1)(mod 11)计算得出。

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
根据上表,查出计算结果为2的校验码为所以该人员的公民身份号码应该为 34052419800101001X。

C#代码:

private string per15To18(string perIDSrc)
{
int iS = 0;

//加权因子常数
int[] iW=new int[]{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
//校验码常数
string LastCode="10X98765432";
//新***号
string perIDNew;

perIDNew=perIDSrc.Substring(0,6);
//填在第6位及第7位上填上‘1’,‘9’两个数字
perIDNew += "19";

perIDNew += perIDSrc.Substring(6,9);

//进行加权求和
for( int i=0; i<17; i++)
{
iS += int.Parse(perIDNew.Substring(i,1)) * iW[i];
}

//取模运算,得到模值
int iY = iS%11;
//从LastCode中取得以模为索引号的值,加到***的最后一位,即为新***号。
perIDNew += LastCode.Substring(iY,1);

return perIDNew;
}



源代码如下:

CREATE OR REPLACE FUNCTION isidCard(str varchar2)
RETURN varchar2
IS
areaID char(6) :=substr(str,1,6);
birthdayID char(8);
sexID char(3);
checkID char(1);
areaStr varchar(20);
birthdayStr1 char(10);
birthdayStr2 char(10);
birthdayStr3 char(10);
birthdayStr4 char(10);
sexStr char(3);
flag char(2);
personInfo varchar2(200);

begin
     if(length(str)!=15 and length(str)!=18)then
        return '长度不对!';
      else
	 select checkarea(areaID) into areaStr from dual;
         if(areaStr!='NULL') then --地址码是否正确           
	    if(length(str)=15) then --15位
               birthdayStr1 :='19'||substr(str,7,6);
	       birthdayStr2 :='20'||substr(str,7,6);
	       select checkbrithday(birthdayStr1) into birthdayStr3 from dual;
	       select checkbrithday(birthdayStr2) into birthdayStr4 from dual;

	       if(birthdayStr3!='NULL' or birthdayStr4!='NULL')then
                     sexID :=substr(str,13,3);
		     select getSex(to_number(sexID)) into sexStr from dual;
                     
		     personInfo :='性别:'||sexStr||' 生日:'||birthdayStr3||'或者'||birthdayStr4||' 地区:'||areaStr;
		     return personInfo;
	       else
                  return '日期错误!';
	       end if;
	    else --18位
                birthdayID :=substr(str,7,8);
                select checkbrithday(birthdayID) into birthdayStr1 from dual;

		if(birthdayStr1!='NULL')then

		select checkCode(str) into flag from dual;
                     if(flag='p')then 
                           sexID :=substr(str,15,3);
			   scott.myprint(sexid);
		           select getSex(to_number(sexID)) into sexStr from dual;

			   personInfo :='性别:'||sexStr||' 生日:'||birthdayStr1||' 地区:'||areaStr;
		           return personInfo;
		     else
                         return '校验码错误!';
		     end if;
                else
                  return '日期错误!';
	        end if;
            end if;
	 else
	   return '地址码错误!';
	 end if;
     end if;
 end;

--地址码
CREATE OR REPLACE FUNCTION checkarea(str varchar2)
return varchar2
is
area varchar2(20);
flag number(2);
begin
     select checkarea1(str) into flag from dual;
     if(flag=1)then
         select substr(idc,7,(length(idc)-6)) into area  from idcardinfo where substr(idc,0,6)=str;
	 return area;
     else
         return 'NULL'; 
     end if;
end;

CREATE OR REPLACE FUNCTION checkarea1(str varchar2)
return number
is
area number(2);
begin
    select count(1) into area from idcardinfo where substr(idc,0,6)=str;
    return area;
end;

--出生日期
CREATE OR REPLACE FUNCTION checkbrithday(str varchar2)
return varchar2
is
birthday varchar2(10);
begin
     select isdate2(str) into birthday from dual;
     if(birthday!='NULL')then
        return birthday;
     else
        return 'NULL';
     end if;
end;
----
CREATE OR REPLACE FUNCTION isdate2(str varchar2)
RETURN varchar
IS
  v_date date;
   v_nls varchar2(100) default null;
BEGIN
   SELECT 'NLS_DATE_LANGUAGE='''||value||''''
      INTO v_nls
      FROM v$nls_parameters
     WHERE parameter='NLS_DATE_LANGUAGE';
  v_date := to_date(str, 'yyyy-mm-dd', v_nls);
  RETURN to_char(v_date,'yyyy-mm-dd');

  EXCEPTION
    WHEN OTHERS THEN
      /*如果你希望看到报错, 就把下面的注释行打开*/
      --raise;
      RETURN 'NULL';
END;
--------------------------------------------------------------------
--性别
CREATE OR REPLACE FUNCTION getSex(str number)
RETURN varchar
is
begin
    if(str mod 2 =0)then
       return '女';
    else
       return '男';
    end if;
end;
--校验码
CREATE OR REPLACE FUNCTION checkCode(str varchar2)
RETURN varchar
is
wi char(35) :='7*9*10*5*8*4*2*1*6*3*7*9*10*5*8*4*2';
checkstr char(11) :='10X98765432';
sumcode number(10);
checkrel number(2);
lastCode char(1);
begin
     sumcode:=to_number(substr(str,1,1))*to_number(substr(wi,1,1))+to_number(substr(str,2,1))*to_number(substr(wi,3,1))+to_number(substr(str,3,1))*to_number(substr(wi,5,2))+to_number(substr(str,4,1))*to_number(substr(wi,8,1))+to_number(substr(str,5,1))*to_number(substr(wi,10,1))+to_number(substr(str,6,1))*to_number(substr(wi,12,1))+to_number(substr(str,7,1))*to_number(substr(wi,14,1))+to_number(substr(str,8,1))*to_number(substr(wi,16,1))+to_number(substr(str,9,1))*to_number(substr(wi,18,1))+to_number(substr(str,10,1))*to_number(substr(wi,20,1))+to_number(substr(str,11,1))*to_number(substr(wi,22,1))+to_number(substr(str,12,1))*to_number(substr(wi,24,1))+to_number(substr(str,13,1))*to_number(substr(wi,26,2))+to_number(substr(str,14,1))*to_number(substr(wi,29,1))+to_number(substr(str,15,1))*to_number(substr(wi,31,1))+to_number(substr(str,16,1))*to_number(substr(wi,33,1))+to_number(substr(str,17,1))*to_number(substr(wi,35,1));
     
     checkrel :=(sumcode mod 11)+1;
     select substr(checkstr,checkrel,1) into lastCode from dual;
     
     if(upper(lastCode)=upper(substr(str,18,1)))then
        return 'p';
      else
        return 'np';
     end if;    
end;

/*
110103198808081226
110103198808121224
11010719880812122x
110101198808121221
110117198808121222
421123198808121223
421125198808121226
42112419880812122x
421123198508121221
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: