本文主要討論的是二代身份證編碼規則及其Java代碼實現,下面的校驗方式還不是特別嚴謹,由於只校驗了前兩位的省份信息,中間六位的出生日期信息和最後一位的校驗碼信息,故對於部分不滿足要求的證件號碼剛好同時滿足了這裏提到的幾個條件,也會被判定爲是合法的證件號碼…
1 二代身份證號碼編碼規則
1.1 編碼格式
1999年我國頒發了第二代居民身份證號,公民身份號碼爲18位,且終身不變。
居民身份證格式如:ABCDEFYYYYMMDDXXXR
1.1.1地址碼(ABCDEF)
表示登記戶口時所在地的行政區劃代碼(省、市、縣),如果行政區劃進行了重新劃分,同一個地方進行戶口登記的可能存在地址碼不一致的情況。行政區劃代碼按GB/T2260的規定執行。
1.1.2 出生日期碼(YYYYMMDD)
表示該居民的出生年月日,年4位數字,月和日分別用2位數字表示,如19491001,;出生日期碼是按GB/T 7408的規定執行的。
1.1.3 順序碼(XXX)
表示同一地址碼區域內,同年、同月、同日生的人所編訂的順序號,根據自己身份證的順序碼就可以知道:與我們同年同月同日生的同性至少有多少個,且在我們之前登記戶籍的有多少人。身份證順序碼的奇數分配給男性,偶數分配給女性。這就是爲什麼倒數第二位奇數表示男生,偶數表示女生。
1.1.4 校驗碼(R)
R之前的17位被稱爲本體碼,R是根據本體碼,按照校驗碼算法(ISO 7064:1983,MOD 11-2校)計算出來的。當我們輸入身份號碼進行實名認證的時候,根據校驗碼算法可以初步判斷你輸入身份證號碼格式是否正確。
1.2 校驗碼算法
將本體碼各位數字乘以對應加權因子並求和,除以11得到餘數,根據餘數通過校驗碼對照表查得校驗碼。
1.2.1 加權因子
位置序號 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
加權因子 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
(本體碼每個位置對應的加權因子)
1.2.2 校驗碼錶
餘數 0 1 2 3 4 5 6 7 8 9 10
校驗碼 1 0 X 9 8 7 6 5 4 3 2
(每個餘數對應的校驗碼)
1.2.3 應用舉例
某公民的身份證號碼是34052419800101001X
第一步:本體碼乘以加權因子:
3*7+4*9+0*10+……0*4+1*2=189
1
第二步:計算求和後除以11的餘數
189%11=2
1
第三步:在檢驗碼中查詢餘數對應的檢驗碼
2所對應的校驗碼是X,注意X必須大寫
2 Java編碼實現
2.1 對外提供的調用接口
/**
* 二代身份證號碼有效性校驗
*
* @param idNo
* @return
*/
public static boolean isValidIdNo(String idNo) {
return isIdNoPattern(idNo) && isValidProvinceId(idNo.substring(0, 2))
&& isValidDate(idNo.substring(6, 14)) && checkIdNoLastNum(idNo);
}
2.2 二代身份證正則表達式
/**
* 二代身份證正則表達式
*
* @param idNo
* @return
*/
private static boolean isIdNoPattern(String idNo) {
return Pattern.matches("^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([\\d|x|X]{1})$", idNo);
}
2.3 校驗前兩位省份信息
2.3.1 常量
//省(直轄市)碼錶
private static String provinceCode[] = { "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" };
2.3.2 檢查省份信息
/**
* 檢查身份證的省份信息是否正確
* @param provinceId
* @return
*/
public static boolean isValidProvinceId(String provinceId){
for (String id : provinceCode) {
if (id.equals(provinceId)) {
return true;
}
}
return false;
}
2.4 判斷中間的六位日期是否有效
/**
* 判斷日期是否有效
* @param inDate
* @return
*/
public static boolean isValidDate(String inDate) {
if (inDate == null){
return false;
}
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
if (inDate.trim().length() != dateFormat.toPattern().length()){
return false;
}
dateFormat.setLenient(false);//執行嚴格的日期匹配
try {
dateFormat.parse(inDate.trim());
} catch (ParseException e) {
return false;
}
return true;
}
2.4 校驗第18位校驗碼
2.4.1 常量
//身份證前17位每位加權因子
private static int[] power = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
//身份證第18位校檢碼
private static String[] refNumber ={"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
2.4.2 計算第18位校驗碼
/**
* 計算身份證的第十八位校驗碼
* @param cardIdArray
* @return
*/
public static String sumPower(int[] cardIdArray){
int result = 0;
for(int i=0;i<power.length;i++){
result += power[i] * cardIdArray[i];
}
return refNumber[(result%11)];
}
2.4.2 驗證第18位校驗碼是否正確
/**
* 校驗身份證第18位是否正確(只適合18位身份證)
* @param idNo
* @return
*/
public static boolean checkIdNoLastNum(String idNo){
if(idNo.length() != 18){
return false;
}
char[] tmp = idNo.toCharArray();
int[] cardidArray = new int[tmp.length-1];
int i=0;
for(i=0;i<tmp.length-1;i++){
cardidArray[i] = Integer.parseInt(tmp[i]+"");
}
String checkCode = sumPower(cardidArray);
String lastNum = tmp[tmp.length-1] + "";
if(lastNum.equals("x")){
lastNum = lastNum.toUpperCase();
}
if(!checkCode.equals(lastNum)){
return false;
}
return true;
}
原文:https://blog.csdn.net/embracejava/article/details/77341740