MaxCompute UDF系列之身份证校验及15位身份证号码转换成18位

本文涉及的产品
云原生大数据计算服务 MaxCompute,5000CU*H 100GB 3个月
云原生大数据计算服务MaxCompute,500CU*H 100GB 3个月
简介: 为了验证一些老证件上的身份证号码到底是不是本人,今天为大家提供一个15位身份证号码转换成18位的MaxCompute的UDF,下载地址见附件。 效果如下: MaxCompute UDF代码如下: /*** * 身份证号码构成:6位地址编码+8位生日+3位顺序码

为了验证一些老证件上的身份证号码到底是不是本人,今天为大家提供一个15位身份证号码转换成18位的MaxCompute的UDF,下载地址见附件。


效果如下:






MaxCompute UDF代码如下:


/*** 
 * 身份证号码构成:6位地址编码+8位生日+3位顺序码+1位校验码 
 * 验证15位,18位证件号码是否有效;15位号码将直接转为18位;
 * 校验身份证号码除了校验位是否为数值,校验省份、出生日期
 * 校验位不正确的会被正确的替代
 * 出生日期逻辑有效性,即是否1900年前出生,是否当前日期后出生未校验
 * 1984年4月6日国务院发布《中华人民共和国居民身份证试行条例》,并且开始颁发第一代居民身份证,按寿命120岁验证,年龄区间是1864年至今。
 * 15位证件号码转换未考虑1900年前出生的人
 ***/
package com.yinlin.udf.dev;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.aliyun.odps.udf.UDF;

public final class IdenNum extends UDF {
  private final static int NEW_CARD_NUMBER_LENGTH = 18;
  private final static int OLD_CARD_NUMBER_LENGTH = 15;
  private final static int YEAR_BEGIN = 1864;
  private final static char[] VERIFY_CODE = { '1', '0', 'X', '9', '8', '7','6', '5', '4', '3', '2' }; // 18位身份证中最后一位校验码
  private final static int[] VERIFY_CODE_WEIGHT = { 7, 9, 10, 5, 8, 4, 2, 1,6, 3, 7, 9, 10, 5, 8, 4, 2 };// 18位身份证中,各个数字的生成校验码时的权值
  private final static int[] PROVINCE_CODE = { 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 };// 省份编码
  private final static Pattern pattern = Pattern.compile("[0-9]*");
  private final static ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<SimpleDateFormat>() {
    protected SimpleDateFormat initialValue() {
      return null;// 直接返回null
    }
  };

  public String evaluate(String cardNumber) {
    if (cardNumber == null) {return null;}// 为NULL
    Date dNow = new Date( );
    SimpleDateFormat ft = new SimpleDateFormat ("yyyy");
    int YEAR_END = Integer.parseInt(ft.format(dNow));
    cardNumber = cardNumber.trim();
    if (cardNumber.length() == 0) {return null;}// 空字符串
    if (NEW_CARD_NUMBER_LENGTH != cardNumber.length() &
        OLD_CARD_NUMBER_LENGTH != cardNumber.length()) {return null;}// 长度不正确
    if (NEW_CARD_NUMBER_LENGTH == cardNumber.length()) {
      if (isNumeric(cardNumber.substring(0, 17)) == false) {return null;} // 前17位为数值
      if (IdenNum.calculateVerifyCode(cardNumber) != cardNumber.charAt(17)) {
         cardNumber = contertToNewCardNumber(cardNumber,NEW_CARD_NUMBER_LENGTH);
      }// 校验位修正
      if (isProvince(cardNumber.substring(0, 2)) == false) {return null;}// 省份编码在已知集合中
      if (isDate(cardNumber.substring(6, 14)) == false) {return null;}// 非法日期转换前后不一致
      int birthdayYear = Integer.parseInt(cardNumber.substring(6, 10));
      if (birthdayYear < YEAR_BEGIN) {return null;}// 为NULL
      if (birthdayYear > YEAR_END) {return null;}// 为NULL
    }
    if (OLD_CARD_NUMBER_LENGTH == cardNumber.length()) {
      if (isNumeric(cardNumber) == false) {return null;} // 前15位为数值
      if (isProvince(cardNumber.substring(0, 2)) == false) {return null;}// 省份编码在已知集合中
      if (isDate("19" + cardNumber.substring(6, 12)) == false) {return null;}// 非法日期转换前后不一致
      cardNumber = contertToNewCardNumber(cardNumber,OLD_CARD_NUMBER_LENGTH);
    }
    return cardNumber;
  }

  /**
   * 校验码(第十八位数):
   * 
   * 十七位数字本体码加权求和公式 S = Sum(Ai * Wi), i = 0...16 ,先对前17位数字的权求和;
   * Ai:表示第i位置上的身份证号码数字值 Wi:表示第i位置上的加权因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4
   * 2; 计算模 Y = mod(S, 11) 通过模得到对应的校验码 Y: 0 1 2 3 4 5 6 7 8 9 10 校验码: 1 0 X 9
   * 8 7 6 5 4 3 2
   * 
   * @param cardNumber
   * @return
   */
  private static char calculateVerifyCode(CharSequence cardNumber) {
    int sum = 0;
    for (int i = 0; i < NEW_CARD_NUMBER_LENGTH - 1; i++) {
      char ch = cardNumber.charAt(i);
      sum += ((int) (ch - '0')) * VERIFY_CODE_WEIGHT[i];
    }
    return VERIFY_CODE[sum % 11];
  }

  /**
   * A-把15位身份证号码转换到18位身份证号码 15位身份证号码与18位身份证号码的区别为:
   * 1、15位身份证号码中,"出生年份"字段是2位,转换时需要补入"19",表示20世纪
   * 2、15位身份证无最后一位校验码。18位身份证中,校验码根据根据前17位生成
   * B-18位身份证号码校验位修复
   * @param cardNumber
   * @return
   */
  private static String contertToNewCardNumber(String CardNumber,int cardNumberLength) {
    StringBuilder buf = new StringBuilder(NEW_CARD_NUMBER_LENGTH);
    if       (cardNumberLength == NEW_CARD_NUMBER_LENGTH){
      buf.append(CardNumber.substring(0, 17));
      buf.append(IdenNum.calculateVerifyCode(buf));
    }else if (cardNumberLength == OLD_CARD_NUMBER_LENGTH){
      buf.append(CardNumber.substring(0, 6));
      buf.append("19");
      buf.append(CardNumber.substring(6));
      buf.append(IdenNum.calculateVerifyCode(buf));
    }
    return buf.toString();
  }

  /**
   * 功能:判断字符串是否为数字
   * 
   * @param str
   * @return
   */
  private static boolean isNumeric(String str) {
    Matcher isNum = pattern.matcher(str);
    if (isNum.matches()) {
      return true;
    } else {
      return false;
    }
  }

  /**
   * 功能:判断前两位是否正确
   * 
   * @param Province
   * @return
   */
  private static boolean isProvince(String Province) {
    int prov = Integer.parseInt(Province);
    for (int i = 0; i < PROVINCE_CODE.length; i++) {
      if (PROVINCE_CODE[i] == prov) {
        return true;
      }
    }
    return false;
  }

  public static SimpleDateFormat getDateFormat() {
    SimpleDateFormat df = (SimpleDateFormat) threadLocal.get();
    if (df == null) {
      df = new SimpleDateFormat("yyyyMMdd");
      df.setLenient(false);
      threadLocal.set(df);
    }
    return df;
  }

  /**
   * 功能:判断出生日期字段是否为日期
   * 
   * @param str
   * @return
   */
  private static boolean isDate(String birthDate) {
    try {
      SimpleDateFormat sdf = getDateFormat();
      Date cacheBirthDate = sdf.parse(birthDate);
      if (sdf.format(cacheBirthDate).equals(birthDate) == false) {return false;}// 非法日期转换前后不一致
    } catch (Exception e) {
      return false;
    }
    return true;
  }

}


使用方法:

1、通过Eclipse将IdenNum.java编译成Jar包,命名为IdenNum_udf.jar。


2、通过大数据开发套件,上传资源IdenNum_udf.jar;




3、通过大数据开发套件,引用第二步上传的IdenNum_udf.jar资源,注册idennum函数;


4、通过大数据开发套件新建SQL脚本,输入SQL函数进行测试。


--创建虚拟表
CREATE TABLE IF NOT EXISTS dual (id STRING);
insert into table dual select '1' from (select count(1) from dual) t;

---idennum身份证有效性识别
select idennum('1101057109235829XX') from yinlin_demo.dual limit 1;

---idennum身份证15位转换18位
select idennum('110105710923582') from yinlin_demo.dual limit 1;


通过MaxCompute CLi客户端(Mac环境)

1、登陆CLI客户端(下载odps_public)


./odpscmd


2、添加Jar包


add jar ~/Downloads/IdenNum_udf.jar;

3、引用Jar并注册函数idennum


CREATE FUNCTION idennum AS com.yinlin.udf.dev.IdenNum USING IdenNum_udf.jar

4、验证结果


select idennum('110105710923582') 



到此为止,实验完成。


常见问题

Q:无结果?

我们在创建虚拟dual表的时候,一定要保证表中有数据。


Q:无法找到函数?

利用大数据开发套件注册函数的时候需要包名+类名,否则会找不到类。



阿里巴巴大数据-玩家社区 https://yq.aliyun.com/teams/6/

---阿里大数据博文,问答,社群,实践,有朋自远方来,不亦说乎……

bba01b493e1c5d904e882b1c380673c6ebe49a98

相关实践学习
基于MaxCompute的热门话题分析
本实验围绕社交用户发布的文章做了详尽的分析,通过分析能得到用户群体年龄分布,性别分布,地理位置分布,以及热门话题的热度。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps&nbsp;
目录
相关文章
|
7月前
|
分布式计算 DataWorks 大数据
MaxCompute产品使用合集之如何使用UDF来使用Protocol Buffers
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
81 15
|
7月前
|
分布式计算 DataWorks 数据处理
MaxCompute操作报错合集之UDF访问OSS,配置白名单后出现报错,是什么原因
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
|
7月前
|
分布式计算 大数据 数据处理
MaxCompute操作报错合集之编写UDF(用户自定义函数)时,报错:找不到主类,是什么原因
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
176 1
|
7月前
|
机器学习/深度学习 分布式计算 大数据
MaxCompute产品使用合集之是否可以将5个资源包统一写到同一个python UDF脚本
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
8月前
|
分布式计算 大数据 调度
MaxCompute产品使用问题之为什么用python写的udf函数跑起来比本地还要慢
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
8月前
|
机器学习/深度学习 分布式计算 DataWorks
MaxCompute产品使用问题之如何在UDF函数中访问外网
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
8月前
|
SQL 分布式计算 大数据
MaxCompute产品使用问题之建了一个python 的 UDF脚本,生成函数引用总是说类不存在,是什么导致的
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
8月前
|
JSON 分布式计算 大数据
MaxCompute产品使用问题之pyODPS3如何引用udf资源的函数
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
8月前
|
分布式计算 大数据 调度
MaxCompute产品使用问题之如何解决UDF针对数据每行操作,而XGBoost需要对数据整体操作的问题
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
7月前
|
分布式计算 大数据 数据处理
MaxCompute操作报错合集之在使用udf遇到报错,是什么原因
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。

相关产品

  • 云原生大数据计算服务 MaxCompute