当前位置: 首页 > Java教程 > 正文

18位居民身份证号码校验工具类(Java)

收藏文章Loading
收藏
(9)
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 身份证工具类,由于现在使用的是二代身份证,所以只验证18位<br>
 * 身份证号码中涉及到行政区划代码,代码不能验证其是否真实存在,所以我们只能验证身份号码逻辑正确性, 并不能验证身份证号码是否真实存在<br>
 * 
 * 身份证组成: 
 * 地址码:(前6位)所在县(市、旗、区)的行政区划代码 
 * 出生日期码:(第7位到第14位)
 * 顺序码:(第15位到17位)县、区级政府所辖派出所的分配码 
 * 校验码:(最后1位)
 **/
public class IDCardUtils {
	
	/**
	 * 基础正则格式:首位非0数字,末位数字或“X”,年份前两位19或20(第7、8位),其他位为数字
	 */
	private final static String REGEX = "^[1-9]\\d{5}(19|20)\\d{9}[\\d|X]$";
	
	/**
	 * 省、直辖市代码表,身份证号的前6位为地址信息,我们只验证前两位
	 */
	private final static Map<String, String> ZONE = new HashMap<String, String>();
	static {
		ZONE.put("11", "北京");
		ZONE.put("12", "天津");
		ZONE.put("13", "河北");
		ZONE.put("14", "山西");
		ZONE.put("15", "内蒙古");
		ZONE.put("21", "辽宁");
		ZONE.put("22", "吉林");
		ZONE.put("23", "黑龙江");
		ZONE.put("31", "上海");
		ZONE.put("32", "江苏");
		ZONE.put("33", "浙江");
		ZONE.put("34", "安徽");
		ZONE.put("35", "福建");
		ZONE.put("36", "江西");
		ZONE.put("37", "山东");
		ZONE.put("41", "河南");
		ZONE.put("42", "湖北");
		ZONE.put("43", "湖南");
		ZONE.put("44", "广东");
		ZONE.put("45", "广西");
		ZONE.put("46", "海南");
		ZONE.put("50", "重庆");
		ZONE.put("51", "四川");
		ZONE.put("52", "贵州");
		ZONE.put("53", "云南");
		ZONE.put("54", "西藏");
		ZONE.put("61", "陕西");
		ZONE.put("62", "甘肃");
		ZONE.put("63", "青海");
		ZONE.put("64", "宁夏");
		ZONE.put("65", "新疆");
		ZONE.put("71", "台湾");
		ZONE.put("81", "香港");
		ZONE.put("82", "澳门");
		ZONE.put("91", "国外");
	}
	
	/**
	 * 每位加权因子
	 */
	private static final int POWER[] = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
	
	/**
	 * 第18位校检码
	 */
	private static final String VERIFY_CODE[] = { "1", "0", "X", "9", "8", "7",	"6", "5", "4", "3", "2" };

	/**
	 * 验证身份证格式
	 * 
	 * @param idCardNo
	 * @return
	 */
	public static boolean verify(String idCardNo) {
		// 1.基础正则格式:首位非0数字,末位数字或“X”,年份前两位19或20(第7、8位),其他位为数字
		if (idCardNo == null || !idCardNo.matches(REGEX)) {
			return false;
		}
		// 2.前两位区域代码校验
		if (!ZONE.containsKey(idCardNo.substring(0, 2))) {
			return false;
		}
		// 3.验证生日
		String birthdayStr = idCardNo.substring(6, 14);
		Date birthday = toBirthDay(birthdayStr);
		SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
		// 转换失败或不相等(生日可能存在输入20187890这种情况)或者大于当前时间都返回false
		if (birthday == null || !birthdayStr.equals(df.format(birthday)) || birthday.after(new Date())) {
			return false;
		}
		// 4.顺序码不作验证,没有规则限制,数字即可
		// 5.验证位验证,计算规则为:身份证前17位数字,对应乘以每位的权重因子,然后相加得到数值X,与11取模获得余数,得到数值Y,通过Y得到校验码。
		if (!idCardNo.substring(17, 18).equals(calcVerifyCode(idCardNo))) {
			return false;
		}
		return true;
	}

	/**
	 * 从身份证号码中获取生日
	 * 
	 * @param idCardNo
	 * @return
	 */
	public static Date getBirthDay(String idCardNo) {
		if (verify(idCardNo)) {
			return toBirthDay(idCardNo.substring(6, 14));
		}
		return null;
	}

	/**
	 * 从身份证号码中获取当前时间年龄,-1:获取失败
	 * 
	 * @param idCardNo
	 * @return age
	 */
	public static int getAge(String idCardNo) {
		return getAge(idCardNo,new Date());
	}
	
	/**
	 * 从身份证号码中获取指定时间点的年龄,-1:获取失败
	 * 
	 * @param idCardNo
	 * @param time
	 * @return age
	 */
	public static int getAge(String idCardNo,Date time) {
		Date birthdate = getBirthDay(idCardNo);
		if (null != birthdate) {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(time);
			int yearNow = calendar.get(Calendar.YEAR);
			int monthNow = calendar.get(Calendar.MONTH) + 1; // 月份从0开始,所以加1
			int dayNow = calendar.get(Calendar.DAY_OF_MONTH);

			calendar.setTime(birthdate);
			int yearBirth = calendar.get(Calendar.YEAR);
			int monthBirth = calendar.get(Calendar.MONTH) + 1; // 月份从0开始,所以加1
			int dayBirth = calendar.get(Calendar.DAY_OF_MONTH);

			int age = yearNow - yearBirth;

			if (monthNow <= monthBirth) {
				if (monthNow == monthBirth) {
					if (dayNow < dayBirth) {
						age--;
					}
				} else {
					age--;
				}
			}
			return age;
		}
		return -1;
	}

	/**
	 * 从身份证号中获取性别 0:获取失败,1:男,2:女
	 * 
	 * @param idCardNo
	 * @return
	 */
	public static int getGender(String idCardNo) {
		if (verify(idCardNo)) {
			// 奇数为男,偶数为女
			return (Integer.parseInt(idCardNo.substring(16, 17)) % 2) == 0 ? 2 : 1;
		}
		return 0;
	}

	// 生日字符串转换为日期
	private static Date toBirthDay(String birthdayStr) {
		try {
			Calendar calendar = Calendar.getInstance();
			calendar.set(Calendar.YEAR,	Integer.parseInt(birthdayStr.substring(0, 4)));
			calendar.set(Calendar.MONTH, Integer.parseInt(birthdayStr.substring(4, 6)) - 1);// 月份从0开始,所以减1
			calendar.set(Calendar.DAY_OF_MONTH,	Integer.parseInt(birthdayStr.substring(6, 8)));

			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			calendar.set(Calendar.MILLISECOND, 0);

			return calendar.getTime();
		} catch (Exception e) {
			return null;
		}
	}

	// 计算验证位。规则为:身份证前17位数字,对应乘以每位的权重因子,然后相加得到数值x,与11取模获得余数y,通过y得到校验码。
	private static String calcVerifyCode(String idCardNo) {
		int sum = 0;
		// 身份证前17位
		char[] fix17 = idCardNo.substring(0, 17).toCharArray();
		for (int i = 0; i < 17; i++) {
			sum += (Integer.parseInt(fix17[i] + "") * POWER[i]); // 每位的权重因子然后求和
		}
		return VERIFY_CODE[sum % 11]; // 与11取模然后得到校验码
	}
}

本文固定链接: http://www.csyor.com/1090.html - 穿梭于偶然

该日志由 Csyor 于2021年04月20日发表在 Java教程 分类下, 通告目前不可用,你可以至底部留下评论。
原创文章转载请注明: 18位居民身份证号码校验工具类(Java) - 穿梭于偶然

18位居民身份证号码校验工具类(Java):等您坐沙发呢!

发表评论

您必须 [ 登录 ] 才能发表留言!