感谢b站的穆哥学堂老师
19-验证特定格式(下)_哔哩哔哩_bilibili
/**
* 身份证号码最后一位的取值数组
*/
public static final String[] CHECK_CODE_ARR = new String[] {"1","0","X","9","8","7","6","5","4","3","2"};
/**
* 身份证号码最后一位数计算的时候的加权因子
*/
public static final int[] POWER_ID_ARR = new int[] {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
/**
* 身份证号码正则校验
*
* @author zhengzhenglei
*/
@Test
public void testIDRegExp() {
String ID = "a81428198921244532";
//1、校验前17位为数字,第18位为x或者数字
boolean flag = Pattern.matches("^\\d{17}[\\dxX]$", ID);
if(!flag) {
System.out.println("格式错误1");
return;
}
// 2、
// 第1个数字,代表的就是所在的大区,共6大区划,分别如下:
// 1-华北局;2-东北局;3-华东局;4-中南局;5-西南局;6-西北局;
// 中国大陆的公民,目前就排到6,而7是给台湾预留的,8代表香港澳门地区(81-香港,82-澳门),9代表海外地区
// 第2位数字代表大区所在的省份,具体如下:
// 华北: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新疆。
String part = ID.substring(0, 2);
String regexp = "(1[1-5]|2[1-3]|3[1-7]|4[1-6]|5[0-4]|6[1-5])";
flag = part.matches(regexp);
if(!flag) {
System.out.println("格式错误2");
return;
}
//3、
// 第3、4位数字表示:所在城市的代码;第5、6位数字表示:所在区县的代码 。这两种代码都不包含00。下面为简易校验,如需详细校验,需要查询三级联动类型的代码集
part = ID.substring(2, 4);
regexp = "0[1-9]|[1-9][0-9]";
flag = part.matches(regexp);
if(!flag) {
System.out.println("格式错误3");
return;
}
//4、
part = ID.substring(4, 6);
regexp = "0[1-9]|[1-9][0-9]";
flag = part.matches(regexp);
if(!flag) {
System.out.println("格式错误4");
return;
}
//5、生日部分
part = ID.substring(6, 14);
flag = checkBirthDay(part);
if(!flag) {
System.out.println("格式错误5");
return;
}
//6
// 身份证最后1位的计算方法
// 明确前提:身份证最左边的数字为第1位
// 计算本体码加权求和值S
// S=第1位号码*第1位加权因子+第2位号码*第2位加权因子+···+第17位号码*第17位加权因子
// 第n位加权因子 =( 2^18-n)%11【2的(18-n)次方然后再用11求模】,加权因子只与位置有关,故是一组固定数值,即上边所写 POWER_ID_ARR
// 计算校验码数组下标 i= S%11
// 校验码数组["1""0""X""9","8""7""6""5""4""3""2")
// 最后一位字符就是根据计算出的下标取自该数组,该字符叫做身份证的校验码
flag = checkLast(ID);
if(!flag) {
System.out.println("格式错误6");
return;
}
System.out.println("格式正确");
}
boolean checkLast(String ID) {
int sum = sumMethod(ID);
String lastCal = getLastCharFromArr(sum);
return ID.endsWith(lastCal);
}
public int sumMethod(String ID) {
int sum = 0;
String str = ID.substring(0, 17);
for(int i=0;i<str.length();i++) {
int s = Integer.parseInt(str.substring(i, i+1));
sum += s*POWER_ID_ARR[i];
}
return sum;
}
//根据身份证本体码加权求和的值取出最后一个字符
public String getLastCharFromArr(int sum) {
return CHECK_CODE_ARR[sum%11];
}
//1880-2040
boolean checkBirthDay(String b) {
int year = Integer.parseInt(b.substring(0, 4));
String mStr = b.substring(4, 6);
int month = Integer.parseInt(mStr);
int day = Integer.parseInt(b.substring(6));
if(year<1880 || year>2040) {
System.out.println("出生年超纲");
return false;
}
if(month<1 || month>12) {
System.out.println("月份不对");
return false;
}
if(day>31) {
System.out.println("每月日期不可超过31天");
return false;
}
//1\3\5\7\8\10\12
if(mStr.matches("04|06|09|11") && day>30) {
System.out.println("平月日期不可超过30天");
return false;
}
if( month ==2) {
if(checkYear(year)) {
if(day>29) {
System.out.println("闰年二月日期不可超过29天");
return false;
}
} else {
if(day>28) {
System.out.println("平年二月日期不可超过28天");
return false;
}
}
}
return true;
}
//判断平年闰年,true为闰年,false为平年
//闰年分为普通闰年和世纪闰年,其判断方法为:公历年份是4的倍数,且不是100的倍数,为普通闰年。公历年份是整百数,且必须是400的倍数才是世纪闰年。归结起来就是通常说的:四年一闰;百年不闰,四百年再闰。
boolean checkYear(int year) {
if((year%100!=0&& year%4==0)||(year%100==0 && year%400==0)){
return true;
}
return false;
}