Java:身份证号码严格校验,与生成
身份证前6位地区码
缘由:现在好多手机端应用,借助互联网实名认证或安全等口号,向用户索取更多的信息,比如绑定身份证。
根据网上关于身份证的百科,我写了一个我认为最严格的校验身份证号码,以及随机生成身份证号的java代码
(网上有很多身份证号检验,随机生成身份证号 的网站)
校验身份证代码
package identity.card;
import java.io.FileReader;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Scanner;
import java.util.Set;
/*
* 身份证组成:2(省级)2(地级市)2(县级)8(出生:年月日)3(派出所代码)1(校验码)
* 其中第17位:奇数=男,偶数=女
加权码wi:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
// 获取校验码:将身份证 (前17位*加权码)所得总和 再对11取余=校验码索引
校验码(18): 1 0 X 9 8 7 6 5 4 3 2
*/
public class IdentityCard {
private static Scanner sc;
public static void main(String[] args) {
try {
idCard();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void idCard() throws Exception {
sc = new Scanner(System.in);
System.out.println("请输入需要校验的身份证号:");
String id = sc.next();// id:身份证号
// 正则初步:校验身份证
// 日期: ((0[1-9])|(1[0-2])):匹配"01-12"月
// (([0-2][1-9])|10|20|30|31):匹配"01-31"天
String regID = "[1-9]\\d{5}[1-9]\\d{3}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9xX]";
if (!id.matches(regID)) {
System.out.println("正则不匹配");
return;
}
// 进一步:年月日校验
int year = Integer.parseInt(id.substring(6, 10));
int month = Integer.parseInt(id.substring(10, 12));
int day = Integer.parseInt(id.substring(12, 14));
System.out.println(year + "," + month + "," + day);
if (day > 28 && !isDate(year, month, day)) {
System.out.println("日期规则不对");
return;
}
// 再进一步:检验最后一位校验码
// 获取加权码wi:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
int[] wi = new int[17];
for (int i = 1; i < 18; i++) {
// 获取加权数字
int winum = (int) (Math.pow(2, i) % 11);
// 将加权数反向存入数组
wi[wi.length - i] = winum;
}
// 获取加权后的总和
int sum = 0;
id = id.trim();// 去空格
for (int i = 0; i < wi.length; i++) {
// 获取身份证前17位的每一位,转换为数字
int j = Integer.parseInt(id.substring(i, i + 1));
// 获取加权后所得的和
sum += (j * wi[i]);
}
// 匹配校验码
String Ai = "10x987654342";
// 获取验证码索引:
int index = sum % 11;
// 比较输入身份证与所得校验码比较(忽略大小写)
if (id.substring(17).equalsIgnoreCase(Ai.substring(index, index + 1))) {
// 判断男女
System.out.println(((Integer.parseInt(id.substring(16, 17)) % 2) == 0) ? "女生" : "男生");
} else {
System.out.println("校验不成功");
return;
}
// isAreacode(id);//按行读取地区编码文档,匹配法
// 最后一步地区码校验.properties集合方法
Properties p = new Properties();
// 加载地区码配置文件
p.load(new FileReader("ID=Zone.txt"));
Set<Entry<Object, Object>> entrySet = p.entrySet();
boolean flag2 = true;
for (Entry<Object, Object> entry : entrySet) {
String key = (String) entry.getKey();
// 匹配身份证所属区域
if (id.substring(0, 6).equals(key)) {
System.out.println(entry.getValue());
flag2 = false;
break;
}
}
if (flag2)
System.out.println("没有此地区:你的身份证有误");
else
System.out.println("读取结束");
}
// 进一步日期判断
public static boolean isDate(int year, int month, int day) {// day=29|30|31
// 日期口诀: 一三五七八十腊(12月),三十一天永不差;平年二月二十八;闰年二月把一加 ;四六九冬(11月)三十日
// 闰年:四年一闰,百年不闰,四百年再闰.
if (month == 2) {// 当月份=2时
if (day == 29 && (year % 4 == 0 && year % 100 != 0 | year % 400 == 0))
return true;
// 是2月非闰年
return false;
}
// 天数是31天,月份却是:4|6|9|11
if (day == 31 && (month == 4 || month == 6 || month == 9 || month == 11))
return false;
// 其它正常情况
return true;
}
}
身份证随机生成方法
public static void diyIdCard() {
// 获取6为地区码
Random ra = new Random();
// 以生成的随机数=循环的次数:来获取随机地区码
int num = ra.nextInt(3465) + 1;
int count = 0;// 循环次数
String str1 = "";// 六位地区码
String zone = "";
Properties p = new Properties();
// 加载地区码配置文件
try {
p.load(new FileReader("ID=Zone.txt"));
} catch (Exception e) {
e.printStackTrace();
}
Set<Entry<Object, Object>> entrySet = p.entrySet();
// 遍历地区码文件
for (Entry<Object, Object> entry : entrySet) {
count++;
// 匹配身份证所属区域
if (num == count) {
str1 = (String) entry.getKey();// 地区码
zone = (String) entry.getValue();// 获取地区
break;
}
}
System.out.println(str1 + ":" + zone);
// 获取年份
Calendar cal = Calendar.getInstance();
// 获取现在年份
int year = cal.get(cal.YEAR);
// 获取150年前到现在的年份
String str2 = Integer.toString(year - ra.nextInt(151));
// 获取月份
String str3 = "";
int month = ra.nextInt(12) + 1;
if (month < 10) {
str3 = "0" + Integer.toString(month);
} else {
str3 = Integer.toString(month);
}
// 获取天
String str4 = "";
int day = ra.nextInt(31) + 1;
if (day < 10) {
str4 = "0" + Integer.toString(day);
} else {
str4 = Integer.toString(day);
}
// 判断生成日期是否符合规则
if (day > 28 && !isDate(year, month, day)) {
System.out.println(year + ":" + month + ":" + day);
// 重新赋值天数
str4 = Integer.toString(day - 3);
System.out.println("日期-天:" + str4);
}
// 获取3位随机数
String str5 = "";
int ran3 = ra.nextInt(1000);
if (ran3 < 10) {
str5 = "00" + Integer.toString(ran3);
} else if (ran3 < 100) {
str5 = "0" + Integer.toString(ran3);
} else {
str5 = Integer.toString(ran3);
}
// 获取校验码
// 获取加权后的总和
String id = str1 + str2 + str3 + str4 + str5;// 前17位ID
// 获取加权码wi:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
int[] wi = new int[17];
for (int i = 1; i < 18; i++) {
// 获取加权数字
int winum = (int) (Math.pow(2, i) % 11);
// 将加权数反向存入数组
wi[wi.length - i] = winum;
}
// 获取加权后的总和
int sum = 0;
for (int i = 0; i < wi.length; i++) {
// 获取身份证前17位的每一位,转换为数字
int j = Integer.parseInt(id.substring(i, i + 1));
// 获取加权后所得的和
sum += (j * wi[i]);
}
// 匹配校验码
String Ai = "10x987654342";
// 获取验证码索引:
int index = sum % 11;
String str6 = Ai.substring(index, index + 1);// 校验码
// 输出身份证
System.out.println(id + str6);
}
// 进一步日期判断
public static boolean isDate(int year, int month, int day) {// day=29|30|31
// 日期口诀: 一三五七八十腊(12月),三十一天永不差;平年二月二十八;闰年二月把一加 ;四六九冬(11月)三十日
// 闰年:四年一闰,百年不闰,四百年再闰.
if (month == 2) {// 当月份=2时
if (day == 29 && (year % 4 == 0 && year % 100 != 0 | year % 400 == 0))
return true;
// 是2月非闰年
return false;
}
// 天数是31天,月份却是:4|6|9|11
if (day == 31 && (month == 4 || month == 6 || month == 9 || month == 11))
return false;
// 其它正常情况
return true;
}