`
caozuiba
  • 浏览: 896272 次
文章分类
社区版块
存档分类
最新评论

新旧身份证合法性验证及相互转换算法

 
阅读更多

新旧身份证合法性验证及相互转换算法
——谨以此文献给共事3年即将离职的PPL

作者:成晓旭

  前天,看到PPL在一个需要网站上注册,但该网站要求输入一个身份证号码,并且随便输入一个还不行:对方还要验证输入身份证的合法性,所以,烦得PPL在网上到处去找。基于此目前,特别在网上收集身份证相关的资料,整理成文,作为给PPL饯行的礼物之一,公布于我的Blog。也预祝PPL:“找份好工作,找个好老婆!”

1、关于中国居民身份证的常识:
  我国现行使用公民身份证号码有两种尊循两个国家标准,〖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 )

  "*" :表示乘号
  i:表示身份证号码每一位的序号,从右至左,最左侧为18,最右侧为1。
  a[i]:表示身份证号码第 i 位上的号码
  W[i]:表示第 i 位上的权值 W[i] = 2^(i-1) mod 11
  设:R = ∑(a[i]*W[i]) mod 11 ( i = 2, 3, ..., 18 )
  C = 身份证号码的校验码
  则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。
2、算法:

/***//**
*
*/

packagecxx.sourceCode.base;

importjava.text.DateFormat;
importjava.text.NumberFormat;
importjava.text.ParseException;
importjava.util.Date;
importjava.util.Random;

/***//**
*
@author成晓旭
*
*/

publicclassIdentity...{
//位权值数组
privatestaticbyte[]Wi=newbyte[17];
//身份证前部分字符数
privatestaticfinalbytefPart=6;
//身份证算法求模关键值
privatestaticfinalbytefMod=11;
//旧身份证长度
privatestaticfinalbyteoldIDLen=15;
//新身份证长度
privatestaticfinalbytenewIDLen=18;
//新身份证年份标志
privatestaticfinalStringyearFlag="19";
//校验码串
privatestaticfinalStringCheckCode="10X98765432";
//最小的行政区划码
privatestaticfinalintminCode=150000;
//最大的行政区划码
privatestaticfinalintmaxCode=700000;
//旧身份证号码
//privateStringoldIDCard="";
//新身份证号码
//privateStringnewIDCard="";
//地区及编码


//privateStringArea[][2]=
privatestaticvoidsetWiBuffer()...{
for(inti=0;i<Wi.length;i++)...{
intk=(int)Math.pow(2,(Wi.length-i));
Wi[i]
=(byte)(k%fMod);
}

}


//获取新身份证的最后一位:检验位
privatestaticStringgetCheckFlag(StringidCard)...{
intsum=0;
//进行加权求和
for(inti=0;i<17;i++)...{
sum
+=Integer.parseInt(idCard.substring(i,i+1))*Wi[i];
}

//取模运算,得到模值
byteiCode=(byte)(sum%fMod);
returnCheckCode.substring(iCode,iCode+1);
}


//判断串长度的合法性
privatestaticbooleancheckLength(finalStringidCard,booleannewIDFlag)...{
booleanright=(idCard.length()==oldIDLen)||(idCard.length()==newIDLen);
newIDFlag
=false;
if(right)...{
newIDFlag
=(idCard.length()==newIDLen);
}

returnright;
}


//获取时间串
privatestaticStringgetIDDate(finalStringidCard,booleannewIDFlag)...{
StringdateStr
="";
if(newIDFlag)
dateStr
=idCard.substring(fPart,fPart+8);
else
dateStr
=yearFlag+idCard.substring(fPart,fPart+6);
returndateStr;
}


//判断时间合法性
privatestaticbooleancheckDate(finalStringdateSource)...{
StringdateStr
=dateSource.substring(0,4)+"-"+dateSource.substring(4,6)+"-"+dateSource.substring(6,8);
System.out.println(dateStr);
DateFormatdf
=DateFormat.getDateInstance();
df.setLenient(
false);
try...{
Datedate
=df.parse(dateStr);
return(date!=null);
}
catch(ParseExceptione)...{
//TODOAuto-generatedcatchblock
returnfalse;
}

}


//旧身份证转换成新身份证号码
publicstaticStringgetNewIDCard(finalStringoldIDCard)...{
//初始化方法
Identity.setWiBuffer();
if(!checkIDCard(oldIDCard))...{
returnoldIDCard;
}

StringnewIDCard
=oldIDCard.substring(0,fPart);
newIDCard
+=yearFlag;
newIDCard
+=oldIDCard.substring(fPart,oldIDCard.length());
Stringch
=getCheckFlag(newIDCard);
newIDCard
+=ch;
returnnewIDCard;
}


//新身份证转换成旧身份证号码
publicstaticStringgetOldIDCard(finalStringnewIDCard)...{
//初始化方法
Identity.setWiBuffer();
if(!checkIDCard(newIDCard))...{
returnnewIDCard;
}

StringoldIDCard
=newIDCard.substring(0,fPart)+
newIDCard.substring(fPart
+yearFlag.length(),newIDCard.length()-1);
returnoldIDCard;
}


//判断身份证号码的合法性
publicstaticbooleancheckIDCard(finalStringidCard)...{
//初始化方法
Identity.setWiBuffer();
booleanisNew=false;
//Stringmessage="";
if(!checkLength(idCard,isNew))...{
//message="ID长度异常";
returnfalse;
}

StringidDate
=getIDDate(idCard,isNew);
if(!checkDate(idDate))...{
//message="ID时间异常";
returnfalse;
}

if(isNew)...{
StringcheckFlag
=getCheckFlag(idCard);
StringtheFlag
=idCard.substring(idCard.length()-1,idCard.length());
if(!checkFlag.equals(theFlag))...{
//message="新身份证校验位异常";
returnfalse;
}

}

returntrue;
}


//获取一个随机的"伪"身份证号码
publicstaticStringgetRandomIDCard(finalbooleanidNewID)...{
//初始化方法
Identity.setWiBuffer();
Randomran
=newRandom();
StringidCard
=getAddressCode(ran)+getRandomDate(ran,idNewID)+getIDOrder(ran);
if(idNewID)...{
Stringch
=getCheckFlag(idCard);
idCard
+=ch;
}

returnidCard;
}


//产生随机的地区编码
privatestaticStringgetAddressCode(Randomran)...{
if(ran==null)...{
return"";
}
else...{
intaddrCode=minCode+ran.nextInt(maxCode-minCode);
returnInteger.toString(addrCode);
}

}


//产生随机的出生日期
privatestaticStringgetRandomDate(Randomran,booleanidNewID)...{
//TODOAuto-generatedmethodstub
if(ran==null)...{
return"";
}

intyear=0;
if(idNewID)...{
year
=1900+ran.nextInt(2007-1900);
}
else...{
year
=1+ran.nextInt(99);
}

intmonth=1+ran.nextInt(12);
intday=0;
if(month==2)...{
day
=1+ran.nextInt(28);
}
elseif(month==1||month==3||month==5||month==7||month==8||month==10||month==12)...{
day
=1+ran.nextInt(31);
}
else...{
day
=1+ran.nextInt(30);
}

NumberFormatnf
=NumberFormat.getIntegerInstance();
nf.setMaximumIntegerDigits(
2);
nf.setMinimumIntegerDigits(
2);
StringdateStr
=Integer.toString(year)+nf.format(month)+nf.format(day);
returndateStr;
}


//产生随机的序列号
privatestaticStringgetIDOrder(Randomran)...{
//TODOAuto-generatedmethodstub
NumberFormatnf=NumberFormat.getIntegerInstance();
nf.setMaximumIntegerDigits(
3);
nf.setMinimumIntegerDigits(
3);
if(ran==null)...{
return"";
}
else...{
intorder=1+ran.nextInt(999);
returnnf.format(order);
}

}


publicIdentity()...{
setWiBuffer();
}

/***//**
*
@paramargs
*/

publicstaticvoidmain(String[]args)...{
//TODOAuto-generatedmethodstub

StringrandomID
=Identity.getRandomIDCard(true);
System.out.println(
"随机身份证:"+randomID);
/**//*
StringoldID="";
StringnewID=Identity.getNewIDCard(oldID);
System.out.println("旧身份证:"+oldID);
System.out.println("新身份证:"+newID);
StringoldCard=Identity.getOldIDCard(newID);
System.out.println("旧身份证:"+oldCard);
/*
StringdateSource="2000-9-30";
if(id.checkDate(dateSource))
System.out.println("正确时间串:"+dateSource);
else
System.out.println("错误时间串:"+dateSource);
*
*
*/

}

}


3、资料参考:
 “将15的身份证号升为18位”:http://www.joyblog.cn/article.asp?id=105
 “一个完整身份证效验程序”:http://www.delphifans.com/InfoView/Article_34.html


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics