中国公民身份证号码校验

中国公民身份证号码校验


上图可看出18位位身份证每一部分表示的意义。

图为随机生成身份号码,四川省 乐山市 井研县 1981年12月28日生


这里主要讲解最后一位校验码的验证

校验码主要是由前面17位数字通过特殊运算得到的,

运算的过程与加权因子又息息相关

编号:      17  16   15  14  13  12  11  10  9   8   7   6   5  4  3  2  1  0

身份信息:5 1     1     1    2    4     1    9    8   1   1   2   2   8  6  8   9  6

加权因子:7    9    10   5    8   4     2   1    6   3   7  9  10  5  8  4  2  1

分别从第一位2的17次方除以11取余,第二位2的16次方除以11取余,以此类推。


这样得到加权因子后,在分别把每一位的身份证号与因子相乘求和。

sum = 5*7+1*9+1*10+1*5+2*8+4*4+1*2+9*1+8*6+1*3+1*7+2*9+2*10+8*5+6*8+8*4+9*2+6*1

再把sum除以11取余,得到的数可以当做是校验码的前身。

因为得到的余数可能是0~10,而实际阿拉伯数字只是0~9,所以用罗马符号X代替一位。

而实际的对应关系确实这样的:

余数           0     1     2     3     4     5     6     7     8     9     10

校验码       1     0     X     9     8     7     6     5     4     3     2


下面是具体的验证方法,写的不好的地方还望大家指正。

import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.regex.Pattern;

public class IdCard {

//	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:"澳门",91:"国外"
	static String[] citycode = { "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", "91" };
	
	//17位加权因子
	//来源,分别从第一位2的17次方除以11取余,第二位2的16次方除以11取余,以此类推
	static int power[] = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 }; 
	
	//11位校验码,这里校验码X用-1表示,对应的是0,1,2,3,4,5,6,7,8,9,10
	static int ai[] = {1,0,-1,9,8,7,6,5,4,3,2};
	
	/**
	 * 对18位身份证做个验证例子。
	 * 考虑到行政区划代码变动情况,这里只验证省
	 * 在这可以查看行政区划代码,http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/
	 * 15位身份证,出生年只有两位,缺少最后一位校验码
	 */
	public static void main(String[] args) {
		String idcard = "511124198112286896";//虚拟的身份证号
		
		
		//简单的正则确认,非空什么的暂时不考虑了
		boolean b = Pattern.matches("^\\d{17}(?:\\d|x|X)$", idcard);
		if(!b)return;
		
		//数组转list,方便查找
		List<String> citycodeList = Arrays.asList(citycode);
		//验证省份
		String province = idcard.substring(0, 2);//省份
		String yearMonthDay = idcard.substring(6, 14);
		int year = Integer.parseInt(idcard.substring(6, 10));//年
		int month = Integer.parseInt(idcard.substring(10, 12));//月
		int day = Integer.parseInt(idcard.substring(12, 14));//日
		
		if(citycodeList.contains(province)){
			Calendar birthday = new GregorianCalendar(year,month-1,day);
			String newyear = String.valueOf(birthday.get(Calendar.YEAR));
			while(newyear.length()<4){
				newyear = "0"+newyear;
			}
			String newmonth = String.valueOf(birthday.get(Calendar.MONTH)+1);
			while(newmonth.length()<2){
				newmonth = "0"+newmonth;
			}
			String newday = String.valueOf(birthday.get(Calendar.DAY_OF_MONTH));
			while(newday.length()<2){
				newday = "0"+newday;
			}
			//校验今天前的日期,和日期的正确性
			if(birthday.before(Calendar.getInstance())&&yearMonthDay.equals(newyear+newmonth+newday)){
				//下面是关键的校验码核对
				checkPower(idcard);
			}else{
				System.out.println("日期不对");
			}
		}else{
			System.out.println("省份不对");
		}
	}
	
	static void checkPower(String idcard){
		if(idcard.length()==18){
			int sum = 0;
			for(int i=0;i<17;i++){
				int temp = Integer.parseInt(String.valueOf(idcard.charAt(i)))*power[i];
				sum += temp;
			}
			int bum = sum%11;
			if(String.valueOf(ai[bum]).toUpperCase().equals(String.valueOf(idcard.charAt(17)).toUpperCase())){
				System.out.println("身份证校验通过");
			}
		}
	}
}

详细的行政区划代码验证可以参考: http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值