设计一个名字为IdCardCheck.java类,实现从键盘输入一个身份证号码字符串,判断输入的字符串是否符合身份证号码的规则,如果符合,计算输出年龄并输出它的年龄,输出你出生在那一年的第几周以及出生到现在已经经过了几周了。如果不符合,提示,并让其重新输入。直到输入正确身份证号码为止。(备注:作业题,描述不算很严谨,大体功能还是明确的)
身份证号码基本格式的校验要用到【正则表达式】和java关于时间的API。题目功能主要是java关于时间的API的运用。
本篇博客主要讲述如何实现:身份证号码的严格校验。讲述大体的实现思路和一些代码的具体实现细节,默认看博客的朋友已经基本了解正则表达式和java有关时间的API。
【地址码】
第1、2位
【生日期码】
略
【顺序码】
【校验码】
1.使用正则表达式校验基本格式
(1)地址码:前6位,其中第1位代表大区,我们可以明确知道第1位一定是1-6中的一个数字。后面的5位都是0-9的数字。
故地址码的正则表达式为:"^[1-6]\\d{5}"
当然,上面还罗列了所有的省份编号(身份证号码第1,2位),在后面可以通过打表去更严格地校验身份证号码的前2位
(2)生日期码
①年:4位,开头两位要么是18(这个可以不需要,因为现在基本上没有是19世纪出生的吧),要么是19,要么是20。后面两位是0-9的数字。正则表达式:"(18|19|20)\\d{2}"
②月:2位。分两种情况:①第1位为0,则第2位为数字0-9;②第1位为1,则第2位为0或1或2。正则表达式:"((0[1-9])|(1[0-2]))"
③日:2位。第1位可能是0,1,2,第2位可能为1-9的数字(为什么不是0-9,因为考虑错判00为正确的情况)。当然不要漏了特殊的几天:10,20,30,31。由于有些月没有31,且考虑2月的特殊性,在后面仍需进一步校验。正则表达式:"(([0-2][1-9])|10|20|30|31)"
(3)顺序码:3位。都是0-9的数字。正则表达式:"\\d{3}"
(4)校验码:校验码是根据前面17位计算出来的,这需要在后面进一步验证。它只能是0-9的数字或者X,x,这我们可以通过正则表达式验证:"[0-9X]"。(这里我不写成"[0-9Xx]"的原因见代码)
2.进一步验证
(1)我们知道身份证号码的第1,2位代表省份(自治区...),省份也就几十个,全部罗列在上面了,我们不妨打表去进一步校验。较简单,见代码
(2)生日期的校验
①身份证号码上面的生日期不能比当前时间还晚(比如说:现在是2019年,身份证号码的生日期是2030年,显然是不对的)
②上面的正则表达式会错判类似以下的情况,比如说:6月31日(事实上6月没有31号,但正则表达式错判为正确);平年2月29日(平年2月是没有29号的,但正则表达式也错判为正确)。这些情况也需要进一步排除,方法也很简单,也是打表,详情见代码
(3)计算校验码
根据前17位计算出相应的检验码(最后一位),如果用户输入的身份证号码的最后一位 与 根据前面17位计算出的校验码不一致,那么这个身份证号码就是错误的
做这个作业(了解身份证号码结构,学习java关于时间的API,敲代码,总结写博客)花了我不少时间,总的来说收获还是蛮大的,写个博客做个笔记。
package theme3;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;
/*
在lesson02中设计一个名字为IdCardCheck.java类,实现从键盘 输入一个身份证号码字符串,
判断输入的字符串是否符合身份证号码的规则,如果符合,计算输出年龄 输出它的年龄,输出你
出生在那一年的第几周以及出生到现在已经经过了几周了。如果不符合,提示,并让其重新输入。
直到输入正确省份证号码为止
*/
public class IdCardCheck {
public static void main(String[] args) throws ParseException {
IdCardCheck ic=new IdCardCheck();
ic.test();
}
//441225200002312559 //检验码正确,但2月份没有31天
//441225201012092558 //生成的正确格式的身份证号码
public void test() throws ParseException
{
Scanner sc=new Scanner(System.in);
String idNum;
do
{
System.out.println("请输入身份证号码:");
idNum=sc.nextLine();
}while(!checkIdCardNum(idNum));
System.out.println("身份证号码\""+idNum+"\"正确!");
System.out.println("持卡人的年龄:"+getYear(idNum));
System.out.println("出生的所在那一周是出生那年的第 "+getBirthWeek(idNum)+" 周");
System.out.println("从出生到现在过去了 "+getWeeks(idNum)+" 周");
}
//身份证号码的严格校验
public boolean checkIdCardNum(String idNum) throws ParseException
{
idNum=idNum.toUpperCase(); //将末尾可能存在的x转成X
String regex="";
regex+="^[1-6]\\d{5}"; //前6位地址码。后面仍需打表校验
regex+="(18|19|20)\\d{2}"; //年份。后面仍需校验
regex+="((0[1-9])|(1[0-2]))"; //月份。后面仍需校验
regex+="(([0-2][1-9])|10|20|30|31)"; //日期。后面仍需校验
regex+="\\d{3}"; //3位顺序码
regex+="[0-9X]"; //检验码。后面仍需验证
if(!idNum.matches(regex))
return false;
//第1,2位(省)打表进一步校验
int[] d={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,53,
61,62,63,64,65,
83,81,82};
boolean flag=false;
int prov=Integer.parseInt(idNum.substring(0, 2));
for(int i=0;icurDate.getTime())
return false;
//生日校验:每个月的天数不一样(有的月份没有31),还要注意闰年的二月
int year=Integer.parseInt(idNum.substring(6, 10));
int leap=((year%4==0 && year%100!=0) || year%400==0)?1:0;
final int[] month={0,31,28+leap,31,30,31,30,31,31,30,31,30,31};
int mon=Integer.parseInt(idNum.substring(10, 12));
int day=Integer.parseInt(idNum.substring(12, 14));
if(day>month[mon])
{
//System.out.println(day+" "+month[mon]+"\n");
//System.out.println("---");
return false;
}
//检验码
if(idNum.charAt(17)!=getLastChar(idNum))
return false;
return true;
}
//根据身份证号码的前17位计算校验码
public char getLastChar(String idNum) //由于这个功能比较独立,就分离出来
{
final int[] w={0,7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
final char[] ch={'1','0','X','9','8','7','6','5','4','3','2'}; //这就是为什么一开始将末尾可能存在的x转成X的原因
int res=0;
for(int i=0;i<17;i++)
{
int t=idNum.charAt(i)-'0';
res+=(t*w[i+1]);
}
return ch[res%11];
}
//根据身份证号码的出生日期计算年龄
public int getYear(String idNum)
{
int yearBirth=Integer.parseInt(idNum.substring(6, 10));
int monBirth=Integer.parseInt(idNum.substring(10, 12));
int dayBirth=Integer.parseInt(idNum.substring(12, 14));
Calendar cur=Calendar.getInstance();
int yearCur=cur.get(Calendar.YEAR);
int monCur=cur.get(Calendar.MONTH)+1; //不要忘了+1
int dayCur=cur.get(Calendar.DATE);
//System.out.println(yearCur+" "+monCur+" "+dayCur);
int age=yearCur-yearBirth;
if(monCur