hive自定义函数-身份证号合法性判断

hive自定义函数-身份证号合法性判断

简要

身份证号合法性判断:
若为18位身份证号:
1.第18位数字,应该在身份证号最后一位校验位数字中
2.前17为数字分别乘以对应的加权因子,累加,结果%11==17为数字
3.数字除18位外,全为数字
若位15位身份证号:
1.验证前6位是为行政区号
2.9-10位为月份<13
3.11-12位为日期<32
4.数据全为数字
注意:数据行政区号全部展示与代码中浏览器中打开时,会导致加载过慢卡顿,所以仅上传了部分数据,全量有*3271条行政区号,需要的评论留言

代码

import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDF;

import java.util.*;


public class UdfIsIdcard extends UDF {
    /**
     * 身份证合法性判断自定义函数
     * 支持15位和18位判断
     */
    /**
     */
    @Description(
            name = "udf_is_idcard",
            value = "_FUNC_(str) - Returns str is idcard?0:1",
            extended = "Example:\n  > SELECT _FUNC_(\'620121199701232548\') FROM dual LIMIT 1;\n   return    0 "
    )

    static int[] weights = {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2}; // 新版身份证号 1-17 位的加权因子. 该数组顺序不能变,和index有对应关系
    static String[] checkCode = {"1","0","X","9","8","7","6","5","4","3","2"}; // 新身份证号最后一位校验位的值. 该数组顺序不能变,和index有对应关系
    static Set<String> newIdCardNoLastNOSet = new HashSet<String>(Arrays.asList(checkCode));
    static Set<String> numberSet = new HashSet<String>(Arrays.asList("9","8","7","6","5","4","3","2","1","0"));
    static Set<String> areaCodeSet = new HashSet<String>(Arrays.asList("110101","110102","110105"));


        public int evaluate(final String idCardNo) {
            if (!basicLegality(idCardNo.trim())) { // 身份证号基础校验不通过,返回false
                return 0;
            }
            if (oldIdCardNoValidate(idCardNo) || newIdCardNoValidate(idCardNo)) {
                return 1;
            }
            return 0;

        }
        /**
         * 身份证号的基本合法性校验。15位保证全是数字,18位保证除最后一位是大写X外,全是数字
         *
         * @return true-验证通过,是身份证号,false-验证不通过,不是身份证号
         */
        private boolean basicLegality(String idCardNo) {
            if (StringUtils.isEmpty(idCardNo) || (idCardNo.length() != 15 && idCardNo.length() != 18)) { // 不是合格的身份证号,新版18位,旧版15位
                return false;
            }
            String number = idCardNo;
            if (idCardNo.length() == 18) { // 新身份证号18位,最后一位可能包含X,单独验证
                String lastNumber = idCardNo.substring(17).toUpperCase();
                boolean contains = newIdCardNoLastNOSet.contains(lastNumber);
                if (!contains) {
                    return false; // 如果不包含在这里面,那么验证不通过
                }
                number = number.substring(0, 17);
            }
            // 做数字验证
            for (int i = 0; i < number.length(); i++) {
                boolean contains = numberSet.contains(String.valueOf(number.charAt(i)));
                if (!contains) {
                    return false; // 如果不包含在这里面,那么验证不通过
                }
            }
            return true;
        }

        /**
         * 验证新版身份证号,有校验位
         * @param newIdCardNo 新版身份证号
         * @return  true-验证通过,是身份证号,false-验证不通过,不是身份证号
         */
        private  boolean newIdCardNoValidate(String newIdCardNo) {
//            if (StringUtils.isEmpty(newIdCardNo) || newIdCardNo.length() != 18) { // 不是合格的新版身份证号
//                return false;
//            }
            int sum = 0; // 此处用int即可。即使每位都是9,求和之后也远远不会溢出,达到int的最大值
            for (int i = 0; i < 17; i++) {
                int c = Integer.parseInt(String.valueOf(newIdCardNo.charAt(i)));
                sum += weights[i] * c;
            }
            int checkCodeIndex = sum % 11;
            return checkCode[checkCodeIndex].equalsIgnoreCase(newIdCardNo.substring(17));
        }



        /**
         *  15位身份证号码各位的含义:
         *1、1-2位省、自治区、直辖市代码;
         *2、3-4位地级市、盟、自治州代码
         *3、5-6位县、县级市、区代码;
         * 4、7-12位出生年月日,比如670401代表1967年4月1日,与18位的第一个区别;
         * 5、13-15位为顺序号,其中15位男为单数,女为双数;
         *
         *
         * 验证旧版身份证号,没有校验位,做是否是数字验证
         * 验证前6位是否为行政区号
         *9-10位小于12
         * 11-12位小于31
         * @param oldIdCardNo 旧版身份证号
         * @return  true-验证通过,是身份证号,false-验证不通过,不是身份证号
         */
        private boolean oldIdCardNoValidate(String oldIdCardNo) {
            boolean flag = false;
//            if(StringUtils.isNotEmpty(oldIdCardNo)&& oldIdCardNo.length() == 15){
//
//            }

            if(areaCodeSet.contains(oldIdCardNo.substring(0,6)) && Integer.parseInt(oldIdCardNo.substring(8,10)) < 13 && Integer.parseInt(oldIdCardNo.substring(10,12)) <32){
                flag =true;
            }
            return flag;
        }

        public static void main(String[] args) {
            System.out.println("值为" + new  UdfIsIdcard().evaluate( "130503670241001"  ));
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值