import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hive.ql.exec.UDF;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
public class CheckSFZ extends UDF {
// 省或直轄市開頭代碼
public static final 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" };
// 最低年限
public static final int MINYear = 1900;
// 加權因子
public static final int power[] = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
// 第18位校檢碼
public static final String lastCode[] = { "X", "9", "8", "7", "6", "5", "4", "3", "2" ,"1", "0" };
// 驗證15位身份編碼是否合法
public boolean validateIdCard15(String idCard) {
if (isNum(idCard)) {
String proCode = idCard.substring(0, 2);
if (!Arrays.asList(cityCode).contains(proCode)){
return false;
}
String birthCode = idCard.substring(6, 12);
Date birthDate = null;
try {
birthDate = new SimpleDateFormat("yy").parse(birthCode.substring(0, 2));
} catch (ParseException e) {
e.printStackTrace();
}
Calendar cal = Calendar.getInstance();
if (birthDate != null)
cal.setTime(birthDate);
if (!valiDate(cal.get(Calendar.YEAR),
Integer.valueOf(birthCode.substring(2, 4)),
Integer.valueOf(birthCode.substring(4, 6)))) {
return false;
}
} else {
return false;
}
return true;
}
// 數字驗證(15位的都是數字)
public static boolean isNum(String val) {
return val == null || "".equals(val) ? false : val
.matches("^[0-9]*");
}
// 驗證小於當前日期 是否有效,
public static boolean valiDate(int iYear, int iMonth, int iDate) {
Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR);
int datePerMonth;
if (iYear < MINYear || iYear >= year) {
return false;
}
if (iMonth < 1 || iMonth > 12) {
return false;
}
switch (iMonth) {
case 4:
case 6:
case 9:
case 11:
datePerMonth = 30;
break;
case 2:
boolean dm = ((iYear % 4 == 0 && iYear % 100 != 0) || (iYear % 400 == 0))
&& (iYear > MINYear && iYear < year);
datePerMonth = dm ? 29 : 28;
break;
default:
datePerMonth = 31;
}
return (iDate >= 1) && (iDate <= datePerMonth);
}
// 15轉18位
public String conver15CardTo18(String idCard) {
String idCard18 = "";
if (idCard.length() != 15) {
return null;
}
if ( (isNum(idCard)) ) {
// 獲取出生年月日
String birthday = idCard.substring(6, 12);
Date birthDate = null;
try {
birthDate = new SimpleDateFormat("yyMMdd").parse(birthday);
} catch (ParseException e) {
e.printStackTrace();
}
Calendar cal = Calendar.getInstance();
if (birthDate != null){
cal.setTime(birthDate);
}
// 獲取出生年(徹底表現形式,如:2010)
String sYear = String.valueOf(cal.get(Calendar.YEAR));
idCard18 = idCard.substring(0, 6) + sYear + idCard.substring(8);
// 轉換字符數組
char[] cArr = idCard18.toCharArray();
if ( (cArr != null) ) {
int[] iCard = converCharToInt(cArr);
int iSum17 = getPowerSum(iCard);
// 獲取校驗位
String sVal = getCheckCode18(iSum17);
if (sVal.length() > 0) {
idCard18 += sVal;
} else {
return null;
}
}
} else {
return null;
}
return idCard18;
}
// 將字符數組轉換成數字數組
public static int[] converCharToInt(char[] ca) {
int len = ca.length;
int[] Arr = new int[len];
try {
for (int i = 0; i < len; i++) {
Arr[i] = Integer.parseInt(String.valueOf(ca[i]));
}
} catch (NumberFormatException e) {
e.printStackTrace();
}
return Arr;
}
// 將身份證的每位和對應位的加權因子相乘以後,再獲得和值
public static int getPowerSum(int[] iArr) {
int iSum = 0;
if (power.length == iArr.length) {
for (int i = 0; i < iArr.length; i++) {
for (int j = 0; j < power.length; j++) {
if (i == j) {
iSum = iSum + iArr[i] * power[j];
}
}
}
}
return iSum;
}
// 將power和值與11取模得到餘數進行校驗碼判斷
public static String getCheckCode18(int iSum) {
String sCode = "";
switch (iSum % 11) {
case 10:
sCode = "2";
break;
case 9:
sCode = "3";
break;
case 8:
sCode = "4";
break;
case 7:
sCode = "5";
break;
case 6:
sCode = "6";
break;
case 5:
sCode = "7";
break;
case 4:
sCode = "8";
break;
case 3:
sCode = "9";
break;
case 2:
sCode = "x";
break;
case 1:
sCode = "0";
break;
case 0:
sCode = "1";
break;
}
return sCode;
}
// 驗證18位身份編碼是否合法
public static boolean validateIdCard18(String idCard) {
boolean bTrue = false;
if(StringUtils.isBlank(idCard)){
return false;
}
if (idCard.length() == 18) {
//地區校驗
String proCode = idCard.substring(0, 2);
if (!Arrays.asList(cityCode).contains(proCode)){
return false;
}
//生日校驗
if(!isDate(idCard)||!isPriDate(idCard)){
return false;
}
//驗證碼校驗
// 前17位
String code17 = idCard.substring(0, 17);
// 第18位
String code18 = idCard.substring(17, 18);
if (!Arrays.asList(lastCode).contains(code18)){ return false;}
if (isNum(code17)) {
char[] cArr = code17.toCharArray();
if ( (cArr != null) ) {
int[] iCard = converCharToInt(cArr);
int iSum17 = getPowerSum(iCard);
// 獲取校驗位
String val = getCheckCode18(iSum17);
if (val.length() > 0) {
if (val.equalsIgnoreCase(code18)) {
bTrue = true;
}
}
}
}
}
return bTrue;
}
// 日期校驗
public static boolean isDate(String idCard){
String dat=idCard.substring(6, 14);
SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMdd");
try {
sdf.setLenient(false);//此處指定日期/時間解析是否不嚴格,在true是不嚴格,false時爲嚴格
sdf.parse(dat);//從給定字符串的開始解析文本,以生成一個日期
}
catch (Exception e) {
return false;
}
return true;
}
// 判斷是不是過去的日期
public static boolean isPriDate(String idCard){
String str=idCard.substring(6, 14);
boolean flag = false;
Date nowDate = new Date();
Date pastDate = null;
//格式化日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd", Locale.CHINA);
//在日期字符串非空時執行
if (StringUtils.isNotBlank(str)) {
try {
//將字符串轉爲日期格式,若是此處字符串爲非合法日期就會拋出異常。
pastDate = sdf.parse(str);
//調用Date裏面的before方法來作判斷
flag = pastDate.before(nowDate);
} catch (ParseException e) {
e.printStackTrace();
}
}
return flag;
}
public String evaluate(String sfzjh){
if(sfzjh == null || "".equals(sfzjh) ){
return "身份證件號有誤";
}
if(sfzjh.length() != 15 && sfzjh.length() != 18){
return "身份證件號有誤";
}
if(sfzjh.length() == 15){
if (!validateIdCard15(sfzjh)){
return "身份證件號有誤";
}
sfzjh = conver15CardTo18(sfzjh);
}
if(sfzjh.length() == 18){ if (!validateIdCard18(sfzjh)){ return "身份證件號有誤"; } } return sfzjh; } /* public static void main(String[] args) { CheckSFZ cf = new CheckSFZ(); String sfzjh = "360731960102400"; System.out.println(cf.evaluate(sfzjh)); }*/}