新旧身份证合法性验证及相互转换算法
——谨以此文献给共事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
分享到:
相关推荐
最完善的身份证号码合法性校验Java算法,适合Android平台,可以直接拿来在项目中使用,正则表达式。
该函数是支持Oracle环境下的对身份照进行校验的函数,它是按照身份照计算算法去校验的,能够精准的判断出身份照是否合法,通过返回值为1:表示为正确的身份证,返回值为0表示为错误的身份证
通过js验证身份证是否有效的js以及身份证的验证算法详解;包括详细的js代码
代码 无向图关联矩阵和邻接矩阵的相互转换算法代码代码 无向图关联矩阵和邻接矩阵的相互转换算法代码代码 无向图关联矩阵和邻接矩阵的相互转换算法代码代码 无向图关联矩阵和邻接矩阵的相互转换算法代码代码 无向图...
代码 有向图关联矩阵和邻接矩阵的相互转换算法代码代码 有向图关联矩阵和邻接矩阵的相互转换算法代码代码 有向图关联矩阵和邻接矩阵的相互转换算法代码代码 有向图关联矩阵和邻接矩阵的相互转换算法代码代码 有向图...
传统拜占庭一致性中常见的中心化和去中心化算法在解决合法性验证的过程中存在容错率低、消息复杂度高等问题,为此,提出新的区块链一致性算法,引入两阶段提交和法定人数投票的过程,利用区块链协议的分布式总账特点...
身份证号码验证算法 (一) 18身份证号码的结构 公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成。 排列顺序从左至右依次为:六位数字地址码 + 八位数字出生日期码 + 三位数字顺序码 + 一位校验码。...
java实现的18位身份证格式验证算法
JAVA身份证号码验证工具,通过身份证号码生成规则,能验证15位、18位身份证号码,必备验证方式
python版身份证识别算法,来源于gitHub开源代码中,目前代码只能运行在ubuntu中,windows版缺少相应的dll文件,如果动手能力强的小伙伴,可以试试找找缺失的dll文件。
这是一个网页源码,身份证的验证。利用JavaScript制作的。
C#实现的18位身份证格式验证算法.txt
根据中国公民身份证号码算法 实现验证身份证号码合法性 已实现java类函数 可直接调用即可 非常方便实用
最新js算法,验证身份证有效性、区域等(含减肥版)
18位身份证号码验证算法.doc
身份证验证javascript验证方法,支持18位和15位身份证校验,算法简单。支持x校验位
身份证最后一位校验位的生成算法,要求输入前17位 计算第18位
C#身份证验证算法归类.pdf
身份证号码验证示例源码 <br>中国身份证号码验证,支持15,18位,可验证成功90%的身份证号 利用正则进行身份证算法验证 <br>非常不错
一个身份证识别的算法,有具体的c语言实现,简洁明了,适合初学者