公民身份号码是特征组合码,由17位数字本体码和1位数字校验码组成。排列顺序从左至右依次为:6位数字地址码、8位数字出生日期码,3位数字顺序码和1位数字校验码。
地址码:表示编码对象常住户口所在县(市、旗、区)的行政区划代码,按 GB/T 2260的规定执行。
出生日期码:表示编码对象的出生年、月、日,按GB/T 7408的规定执行。
顺序码:表示在同一地址码所标识的区域范围内,对同年,同月,同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配给女性。
校验码:校验码采用ISO 7064: 1983, MOD 11-2校验码系统。
一、关键技术点
1、求验证码的方法是:
对前17位数字本体码加权求和,公式为:S = Sum(Ai * Wi),i = 0,......,16,其中Ai表示第i位置上的身份证号码数字值,Wi表示第i位置上的加权因子,加权因子的值从0到16位分别为7、9、10、5、8、4、2、1、6、3、7、9、10、5、8、4、2。
然后对S取模,公式为:Y = mod(S,11)。
然后通过模Y得到对应的校验码。对应关系为<0,1>,<1,0>,<2,X>,<3,9>,<4,8>,<5,7>,<6,6>,<7,5>,<8,4>,<9,3>,<10,2>。关系中前者为Y值,后者为对应的校验码。
二、演示实例
* 文件名IDCard.java
*/
package book.oo.String;
public class IDCard ... {
private static final int[] weight = new int[] ...{ 7, 9, 10, 5, 8, 4, 2, 1, 6,
3, 7, 9, 10, 5, 8, 4, 2, 1 }; // 加权因子
private static final int[] checkDigit = new int[] ...{ 1, 0, 'X', 9, 8, 7, 6,
5, 4, 3, 2, };
public IDCard() ...{
}
/** *//**
* 计算18位身份证的校验码
*/
private String getCheckDigit(String eighteenCardId) ...{
int remaining = 0;
//先取得18位身份证的17位本体码
if(eighteenCardId.length() == 18) ...{
eighteenCardId = eighteenCardId.substring(0, 17);
}
//根据公式对本体码进行加权求和
if(eighteenCardId.length() == 17) ...{
int sum = 0;
int[] a = new int[17];
//先对前17位数字的权求和
for(int i = 0; i < 17; i++) ...{
String k = eighteenCardId.substring(i, i+1);
a[i] = Integer.parseInt(k);
}
for(int i = 0; i < 17; i++) ...{
sum = sum + weight[i] * a[i];
}
//再与11取模
remaining = sum % 11;
}
//返回校验码
return remaining == 2 ? "X" : String.valueOf(checkDigit[remaining]);
}
/** *//**
* 将15位身份证号码升级为18位身份证号码
*/
private String update2eighteen(String fifteenCardID) ...{
//15位身份证上的生日的年份没有加19,要加上
String eighteenCardID = fifteenCardID.substring(0,6);
eighteenCardID = eighteenCardID + "19";
eighteenCardID = eighteenCardID + fifteenCardID.substring(6,15);
eighteenCardID = eighteenCardID + this.getCheckDigit(eighteenCardID);
return eighteenCardID;
}
/** *//**
* 验证身份证是否符合格式
*/
public boolean verify(String idcard) ...{
if(idcard.length() == 15) ...{
idcard = this.update2eighteen(idcard);
}
if(idcard.length() != 18) ...{
return false;
}
//获取身份证上的最后一位,它是校验码
String checkDigit = idcard.substring(17,18);
//比较获取的校验码与生成的校验码是否相等
if (checkDigit.equals(this.getCheckDigit(idcard))) ...{
return true;
}
return false;
}
public static void main(String[] args) ...{
IDCard test = new IDCard();
String idCardStr = "110105194912310025";
System.out.println("身份证:" + idCardStr + "验证合格?" + test.verify(idCardStr));
idCardStr = "632826198011290019";
System.out.println("身份证:" + idCardStr + "验证合格?" + test.verify(idCardStr));
}
}
输出结果:
身份证:110105194912310025验证合格?false
身份证:632826198011290019验证合格?true