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() == 18){
if (!validateIdCard18(sfzjh)){
return "身份证件号有误";
}
}
if(sfzjh.length() == 15){
if (!validateIdCard15(sfzjh)){
return "身份证件号有误";
}
sfzjh = conver15CardTo18(sfzjh);
}
return sfzjh;
}
/* public static void main(String[] args) {
CheckSFZ cf = new CheckSFZ();
String sfzjh = "360731960102400";
System.out.println(cf.evaluate(sfzjh));
}
*/
}