身份证验证的工具
import java.text.DateFormat; | |
import java.text.SimpleDateFormat; | |
import java.util.Calendar; | |
import java.util.HashMap; | |
import java.util.Map; | |
import java.util.regex.Pattern; | |
/** | |
* IDCardUtil | |
* <p> | |
* 身份证验证的工具(支持15位或18位身份证) | |
* 身份证号码结构: | |
* 17位数字和1位校验码:6位地址码数字,8位生日数字,3位出生时间顺序号,1位校验码。 | |
* 地址码(前6位):表示对象常住户口所在县(市、镇、区)的行政区划代码,按GB/T2260的规定执行。 | |
* 出生日期码,(第七位 至十四位):表示编码对象出生年、月、日,按GB按GB/T7408的规定执行,年、月、日代码之间不用分隔符。 | |
* 顺序码(第十五位至十七位):表示在同一地址码所标示的区域范围内,对同年、同月、同日出生的人编订的顺序号, | |
* 顺序码的奇数分配给男性,偶数分配给女性。 | |
* 校验码(第十八位数): | |
* 十七位数字本体码加权求和公式 s = sum(Ai*Wi), i = 18…2,先对前17位数字的权求和; | |
* Ai:表示第i位置上的身份证号码数字值。 | |
* Wi:表示第i位置上的加权因子,采用的是国际标准化组织ISO订立的《ISO 7064: 1983》中的“MOD 11-2”校验码系统。 | |
* 计算方法是 2的 i-1 次方除以11的余数,公式: Wi = mod( 2^(i-1) , 11) , | |
* 计算后的结果 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2; | |
* 计算模, 本体码除以11的余数 Y = mod(s, 11) | |
* 通过模得到对应的校验码 Y: 0 1 2 3 4 5 6 7 8 9 10 <=> 校验码: 1 0 X 9 8 7 6 5 4 3 2 | |
* | |
* @author chingow | |
* @date 2019/11/27 20:45 | |
*/ | |
public class IDCardUtil { | |
final static Map<Integer, String> zoneNum = new HashMap<>(); | |
final static int[] POWER_LIST = new int[17]; | |
static Pattern pattern = Pattern.compile("^\\d{17}[\\d|X]$"); | |
static { | |
zoneNum.put(11, "北京"); | |
zoneNum.put(12, "天津"); | |
zoneNum.put(13, "河北"); | |
zoneNum.put(14, "山西"); | |
zoneNum.put(15, "内蒙古"); | |
zoneNum.put(21, "辽宁"); | |
zoneNum.put(22, "吉林"); | |
zoneNum.put(23, "黑龙江"); | |
zoneNum.put(31, "上海"); | |
zoneNum.put(32, "江苏"); | |
zoneNum.put(33, "浙江"); | |
zoneNum.put(34, "安徽"); | |
zoneNum.put(35, "福建"); | |
zoneNum.put(36, "江西"); | |
zoneNum.put(37, "山东"); | |
zoneNum.put(41, "河南"); | |
zoneNum.put(42, "湖北"); | |
zoneNum.put(43, "湖南"); | |
zoneNum.put(44, "广东"); | |
zoneNum.put(45, "广西"); | |
zoneNum.put(46, "海南"); | |
zoneNum.put(50, "重庆"); | |
zoneNum.put(51, "四川"); | |
zoneNum.put(52, "贵州"); | |
zoneNum.put(53, "云南"); | |
zoneNum.put(54, "西藏"); | |
zoneNum.put(61, "陕西"); | |
zoneNum.put(62, "甘肃"); | |
zoneNum.put(63, "青海"); | |
zoneNum.put(64, "新疆"); | |
zoneNum.put(71, "台湾"); | |
zoneNum.put(81, "香港"); | |
zoneNum.put(82, "澳门"); | |
zoneNum.put(91, "外国"); | |
} | |
static { | |
// 初始化加权因子 Wi | |
for (int i = 0; i < 17; i++) { | |
// 计算方法是 2的17-i 次方除以11的余数,公式: Wi = mod( 2^(17-i) , 11) , | |
POWER_LIST[i] = (int) Math.pow(Double.valueOf(2), Double.valueOf(17 - i)) % 11; | |
} | |
} | |
final static char[] PARITY_BIT = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'}; | |
/** | |
* 身份证验证 | |
* | |
* @param certNo 身份证号码 | |
* @return 是否有效 null和"" 都是false | |
*/ | |
public static boolean isIDCard(String certNo) { | |
if (certNo == null || !pattern.matcher(certNo = certNo.toUpperCase()).matches()) { | |
return false; | |
} | |
//校验区位码 | |
if (!zoneNum.containsKey(Integer.valueOf(certNo.substring(0, 2)))) { | |
return false; | |
} | |
//校验出生日期码 | |
String birthday = certNo.length() == 15 ? "19" + certNo.substring(6, 12) : certNo.substring(6, 14); | |
DateFormat fmt = new SimpleDateFormat("yyyyMMdd"); | |
try { | |
// 如果日期超过当前时间说明日期错误 | |
if (fmt.parse(birthday).after(Calendar.getInstance().getTime())) { | |
return false; | |
} | |
} catch (Exception e) { | |
// 如果throw java.text.ParseException或者NullPointerException,就说明格式不对 | |
return false; | |
} | |
//校验"校验码" , 15 位不需要校验 | |
if (certNo.length() == 15) { | |
return true; | |
} | |
return certNo.substring(17).equals(String.valueOf(getCheckCode(certNo))); | |
} | |
/** | |
* 获取18位身份证号码 | |
* | |
* @param certNo 身份证号码 | |
* @return 15位身份证号转化为18位返回,非15位身份证号原值返回 | |
*/ | |
public static String get18Ic(String certNo) { | |
if (certNo == null || certNo.length() != 15) { | |
return certNo; | |
} | |
// 1999年10月开始实行18位身份证号码,故15位身份证号码都是19XX年的 | |
String ic17 = new StringBuffer() | |
.append(certNo.substring(0, 6)) | |
.append("19") | |
.append(certNo.substring(6)).toString(); | |
return ic17 + getCheckCode(ic17); | |
} | |
/** | |
* 获取身份证号码校验码 | |
* | |
* @param certNo | |
* @return | |
*/ | |
private static char getCheckCode(String certNo) { | |
char[] cs = certNo.toCharArray(); | |
//校验位数 | |
int power = 0; | |
// 取身份证前17位 | |
for (int i = 0; i < 17; i++) { | |
power += (cs[i] - '0') * POWER_LIST[i]; | |
} | |
return PARITY_BIT[power % 11]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment