身份证号码构成:6位地址编码,8位生日,3位顺序码和1位校验码
6位地址编码:表示编码对象常住户口所在县(市、旗、区)的行政区域划分代码,按GB/T2260的规定执行
8位生日:表示编码对象出生的年、月、日,按GB/T7408的规定执行,年、月、日代码之间不用分隔符和空格。
3位顺序码:表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,注意:顺序码的奇数分配给男性,偶数分配给女性。
1位校验码:校验码是根据前面十七位数字码,按照ISO 7064:1983.MOD 11-2校验码计算出来的检验码。
校验位的计算:
通过S = Sum(Ai * Wi), i = 0, ... , 16 ,先对前17位数字的权求和
Y = mod(S, 11)
i: 表示号码字符从右至左包括校验码字符在内的位置序号
Ai:表示第i位置上的身份证号码字符值
Wi:表示第i位置上的加权因子
i: 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 1
其中加权因子的由来
第一项 2^(18-1)%11=131072%11=7 第二项:2^(17-1)%11=65536%11=9 第三项 2^15%11=32768%11=10 第四项:2^14%11=16384%11=5......................第15项:2^(4-1)%11=8,第16项:2^(3-1)%11=4第17项:2^(2-1)%11=2 第18项:2(1-1)%11=1
最后一位值对应的校验码字符值:
Y: 0 1 2 3 4 5 6 7 8 9 10
校验码: 1 0 X 9 8 7 6 5 4 3 2
比如身份证号:14010519921101051* 求*所代表的值
Ai: 1 4 0 1 0 5 1 9 9 2 1 1 0 1 0 5 1 *
Wi:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 1
S = Ai * Wi=7+36+0+5+0+20+2+9+54+6+7+9+0+5+0+20+2=175
S=175/11=15+10/11
Y = mod(S, 11)=mod(217,11)=10
第十位所对应的校验码为2,所以*为2
身份证号为:140105199211010512
代码修改自http://blog.csdn.net/cecoo/article/details/4954522
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Date:2015/9/7.
*/
public class IDCard {
public static String IDCardValidate(String IDStr) {
String errorInfo = "";// 记录错误信息
String[] ValCodeArr = { "1", "0", "x", "9", "8", "7", "6", "5", "4","3", "2" };
String[] Wi = { "7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7","9", "10", "5", "8", "4", "2" };
String Ai = "";
String cityCode[] = { "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", "71", "81", "82", "91" };//省份
if (IDStr.length() != 15 && IDStr.length() != 18) {
errorInfo = "身份证号码长度应该为15位或18位。";
return errorInfo;
}
if (IDStr.length() == 18) {
Ai = IDStr.substring(0, 17);
}else if (IDStr.length() == 15){
Ai = IDStr.substring(0, 6) + "19" + IDStr.substring(6, 15);
}
if (isNumeric(Ai) == false) {
errorInfo = "身份证15位号码都应为数字 ; 18位号码除最后一位外,都应为数字。";
return errorInfo;
}
String provinceid = IDStr.substring(0, 2);
boolean flag = false;
for (String id : cityCode) {
if (id.equals(provinceid)) {
flag = true;
break;
}
}
if (!flag) {
errorInfo = "身份证省份无效。";
return errorInfo;
}
String strYear = Ai.substring(6, 10);// 年份
String strMonth = Ai.substring(10, 12);// 月份
String strDay = Ai.substring(12, 14);// 日份
if (isDate(strYear + "-" + strMonth + "-" + strDay) == false) {
errorInfo = "身份证生日无效。";
return errorInfo;
}
GregorianCalendar gc = new GregorianCalendar();
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");
try {
if ((gc.get(Calendar.YEAR) - Integer.parseInt(strYear)) > 150
|| (gc.getTime().getTime() - s.parse(
strYear + "-" + strMonth + "-" + strDay).getTime()) < 0) {
errorInfo = "身份证生日不在有效范围。";
return errorInfo;
}
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (java.text.ParseException e) {
e.printStackTrace();
}
if (Integer.parseInt(strMonth) > 12 || Integer.parseInt(strMonth) == 0) {
errorInfo = "身份证月份无效";
return errorInfo;
}
if (Integer.parseInt(strDay) > 31 || Integer.parseInt(strDay) == 0) {
errorInfo = "身份证日期无效";
return errorInfo;
}
int TotalmulAiWi = 0;
for (int i = 0; i < 17; i++) {
TotalmulAiWi = TotalmulAiWi
+ Integer.parseInt(String.valueOf(Ai.charAt(i)))
* Integer.parseInt(Wi[i]);
}
int modValue = TotalmulAiWi % 11;
String strVerifyCode = ValCodeArr[modValue];
Ai = Ai + strVerifyCode;
if (IDStr.length() == 18) {
if (Ai.equals(IDStr) == false) {
errorInfo = "身份证无效,不是合法的身份证号码";
return errorInfo;
}
} else {
return "";
}
return "";
}
/**
* 功能:判断字符串是否为数字
*
* @param str
* @return
*/
private static boolean isNumeric(String str) {
Pattern pattern = Pattern.compile("[0-9]*");
Matcher isNum = pattern.matcher(str);
if (isNum.matches()) {
return true;
} else {
return false;
}
}
/**
* 功能:
* @param strDate YYYY-MM-DD
* @return
*/
public static boolean isDate(String strDate) {
Pattern pattern = Pattern.compile("(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0
[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)");
Matcher m = pattern.matcher(strDate);
if (m.matches()) {
return true;
} else {
return false;
}
}
public static void main(String[] args) throws ParseException {
String IDCardNums="430421197710177894";
IDCard cc = new IDCard();
System.out.println(cc.IDCardValidate(IDCardNum));
System.out.println(cc.isDate("1996-01-31"));
}
}
代码修改自http://blog.csdn.net/cecoo/article/details/4954522 代码主要修改了将年月日通过正则表达式中加入了闰年和平年的判定,将省份的判断减少了代码