Created
July 24, 2015 06:41
-
-
Save chanjarster/0979fa9471e40514e9b1 to your computer and use it in GitHub Desktop.
中国大陆身份证号Parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.text.ParseException; | |
import java.text.SimpleDateFormat; | |
import java.util.Date; | |
/** | |
* 中国居民身份证parser,支持15位,18位身份证 | |
* http://www.360doc.com/content/11/0322/21/4240950_103674335.shtml | |
* http://baike.baidu.com/view/3457576.htm | |
* Created by qianjia on 15/7/22. | |
*/ | |
public class IdcardParser { | |
//wi =2(n-1)(mod 11) | |
private static final int[] wi = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1 }; | |
// verify digit | |
private static final int[] vi = { 1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2 }; | |
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); | |
/** | |
* 错误信息 | |
*/ | |
private String error; | |
/** | |
* 18位身份证号 | |
*/ | |
private String idcard18; | |
/** | |
* 省份(自治区,直辖市) | |
*/ | |
private String province; | |
/** | |
* 市(州) | |
*/ | |
private String city; | |
/** | |
* 县(县级市) | |
*/ | |
private String district; | |
/** | |
* 出生日期 | |
*/ | |
private Date birthday; | |
/** | |
* 当地派出所 | |
*/ | |
private String policeStation; | |
/** | |
* 性别 1:男,2:女 | |
*/ | |
private String gender; | |
public IdcardParser(String idcard) { | |
if (idcard == null || idcard.length() == 0) { | |
error = "身份证号为null"; | |
return; | |
} | |
if (idcard.length() != 15 && idcard.length() != 18) { | |
error = "身份证号长度不正确,必须是15位或者18位"; | |
return; | |
} | |
idcard = idcard.toUpperCase(); | |
if (verifyLength(idcard) | |
&& verifyCharLegal(idcard)) { | |
this.idcard18 = convertTo18Digits(idcard); | |
if (verifyProvince() | |
&& verifyCity() | |
&& verifyDistrict() | |
&& verifyBirthday() | |
&& verifyPoliceStation() | |
&& verifyGender() | |
&& verifyVerifyDigit()) { | |
// 利用短路 && | |
} | |
} | |
} | |
/** | |
* 检验长度 | |
* | |
* @param idcard | |
* @return | |
*/ | |
private boolean verifyLength(String idcard) { | |
if (idcard == null || idcard.length() == 0) { | |
error = "身份证号长度不正确,必须是15位或者18位"; | |
return false; | |
} | |
if (idcard.length() != 15 && idcard.length() != 18) { | |
error = "身份证号长度不正确,必须是15位或者18位"; | |
return false; | |
} | |
return true; | |
} | |
/** | |
* 校验字符是否合法 | |
* | |
* @param idcard | |
* @return | |
*/ | |
private boolean verifyCharLegal(String idcard) { | |
char[] ch = idcard.toCharArray(); | |
for (int i = 0; i < ch.length; i++) { | |
if (i == 17) { | |
if (!( | |
(ch[i] >= '0' && ch[i] <= '9') || ch[i] == 'X' | |
)) { | |
error = "第" + (i + 1) + "位包含非法字符"; | |
return false; | |
} | |
} else { | |
if (!(ch[i] >= '0' && ch[i] <= '9')) { | |
error = "第" + (i + 1) + "位包含字母"; | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
/** | |
* 15位转18位身份证 | |
* | |
* @param idcard | |
* @return | |
*/ | |
private String convertTo18Digits(String idcard) { | |
if (idcard.length() == 18) { | |
return idcard; | |
} | |
if (idcard.length() == 15) { | |
verifyAllDigit(idcard); | |
} | |
String idcard18 = idcard.substring(0, 6); | |
idcard18 = idcard18 + "19"; | |
idcard18 = idcard18 + idcard.substring(6, 15); | |
idcard18 = idcard18 + calculateVerifyDigit(idcard18); | |
return idcard18; | |
} | |
//验证身份除了最后位其他的是否包含字母 | |
private boolean verifyAllDigit(String idcard) { | |
String str = idcard; | |
return true; | |
} | |
/** | |
* 检验省份(自治区,直辖市) | |
* | |
* @return | |
*/ | |
private boolean verifyProvince() { | |
this.province = idcard18.substring(0, 2); | |
return true; | |
} | |
/** | |
* 检验市(州) | |
* | |
* @return | |
*/ | |
private boolean verifyCity() { | |
this.city = idcard18.substring(2, 4); | |
return true; | |
} | |
/** | |
* 检验县(县级市) | |
* | |
* @return | |
*/ | |
private boolean verifyDistrict() { | |
this.district = idcard18.substring(4, 6); | |
return true; | |
} | |
/** | |
* 检验出生日期 | |
* | |
* @return | |
*/ | |
private boolean verifyBirthday() { | |
try { | |
this.birthday = sdf.parse(idcard18.substring(6, 14)); | |
return true; | |
} catch (ParseException e) { | |
this.error = "出生日期错误(15位身份证: 7-12位, 18位身份证: 7-14位)"; | |
} | |
return false; | |
} | |
/** | |
* 检验当地派出所 | |
* | |
* @return | |
*/ | |
private boolean verifyPoliceStation() { | |
this.policeStation = idcard18.substring(14, 16); | |
return true; | |
} | |
/** | |
* 检验性别 | |
* | |
* @return | |
*/ | |
public boolean verifyGender() { | |
this.gender = Integer.parseInt(idcard18.substring(16, 17)) % 2 == 0 ? "2" : "1"; | |
return true; | |
} | |
/** | |
* 检验校验位 | |
* | |
* @return | |
*/ | |
private boolean verifyVerifyDigit() { | |
String actualMod = idcard18.substring(17, 18); | |
String expectedMod = calculateVerifyDigit(idcard18); | |
if (actualMod.equals(expectedMod)) { | |
return true; | |
} | |
error = "最末尾的数字验证码错误"; | |
return false; | |
} | |
/** | |
* 身份证号码是否合法 | |
* | |
* @return | |
*/ | |
public boolean isValid() { | |
return error == null || error.length() == 0; | |
} | |
/** | |
* 获得校验位 | |
* | |
* @param idcard18 | |
* @return | |
*/ | |
private String calculateVerifyDigit(String idcard18) { | |
int[] ai = new int[18]; | |
int remaining = 0; | |
if (idcard18.length() == 18) { | |
idcard18 = idcard18.substring(0, 17); | |
} | |
if (idcard18.length() == 17) { | |
int sum = 0; | |
for (int i = 0; i < 17; i++) { | |
String k = idcard18.substring(i, i + 1); | |
ai[i] = Integer.parseInt(k); | |
} | |
for (int i = 0; i < 17; i++) { | |
sum = sum + wi[i] * ai[i]; | |
} | |
remaining = sum % 11; | |
} | |
return String.valueOf(vi[remaining]); | |
} | |
public String getError() { | |
return error; | |
} | |
/** | |
* 获得18位形式身份证号 | |
* | |
* @return | |
*/ | |
public String getIdcard18() { | |
return idcard18; | |
} | |
/** | |
* 省份(自治区,直辖市) | |
* | |
* @return | |
*/ | |
public String getProvince() { | |
return province; | |
} | |
/** | |
* 市(州) | |
* | |
* @return | |
*/ | |
public String getCity() { | |
return city; | |
} | |
/** | |
* 县(县级市) | |
* | |
* @return | |
*/ | |
public String getDistrict() { | |
return district; | |
} | |
/** | |
* 出生日期 | |
* | |
* @return | |
*/ | |
public Date getBirthday() { | |
return birthday; | |
} | |
/** | |
* 当地派出所 | |
* | |
* @return | |
*/ | |
public String getPoliceStation() { | |
return policeStation; | |
} | |
/** | |
* 性别 1:男,2:女 | |
* | |
* @return | |
*/ | |
public String getGender() { | |
return gender; | |
} | |
} |
Author
chanjarster
commented
Jul 24, 2015
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment