原创

Java验证身份证号是否合法

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/jianggujin/article/details/51733032

身份证作为居民的唯一标识。在很多系统中需要用户输入身份证号信息,今天我们就来编写一个方法验证身份证号的合法性。

首先我们来看看身份证号的编码规则:
前1-2位数字表示:所在省(直辖市、自治区)的代码;
第3-4位数字表示:所在地级市(自治州)的代码;
第5-6位数字表示:所在区(县、自治县、县级市)的代码;
第7-14位数字表示:出生年、月、日;
第15-16位数字表示:所在地的派出所的代码;
第17位数字表示性别:奇数表示男性,偶数表示女性;
第18位数字是校检码:也有的说是个人信息码,不是随计算机的随机产生,它是 用来检验身份证的正确性。校检码可以是0-9的数字,有时也用X表示。

知道了规则之后,我们再来看看算法:
第一步:将身份证号码的第1位数字与7相乘;将身份证号码的第2位数字与9相乘;将身份证号码的第3位数字与10相乘;将身份证号码的第4位数字与5相乘;将身份证号码的第5位数字与8相乘;将身份证号码的第6位数字与4相乘;将身份证号码的第7位数字与2相乘;将身份证号码的第8位数字与1相乘;将身份证号码的第9位数字与6相乘;将身份证号码的第10位数字与3相乘;将身份证号码的第11位数字与7相乘;将身份证号码的第12位数字与9相乘;将身份证号码的第13位数字与10相乘;将身份证号码的第14位数字与5相乘;将身份证号码的第15位数字与8相乘;将身份证号码的第16位数字与4相乘;将身份证号码的第17位数字与2相乘。
第二步:将第一步身份证号码1~17位相乘的结果求和,全部加起来。
第三步:用第二步计算出来的结果除以11,这样就会出现余数为0,余数为1,余数为2,余数为3,余数为4,余数为5,余数为6,余数为7,余数为8,余数为9,余数为10共11种可能性。
第四步:如果余数为0,那对应的最后一位身份证的号码为1;如果余数为1,那对应的最后一位身份证的号码为0;如果余数为2,那对应的最后一位身份证的号码为X;如果余数为3,那对应的最后一位身份证的号码为9;如果余数为4,那对应的最后一位身份证的号码为8;如果余数为5,那对应的最后一位身份证的号码为7;如果余数为6,那对应的最后一位身份证的号码为6;如果余数为7,那对应的最后一位身份证的号码为5;如果余数为8,那对应的最后一位身份证的号码为4;如果余数为9,那对应的最后一位身份证的号码为3;如果余数为10,那对应的最后一位身份证的号码为2。

了解了身份证号的规则之后,我们就可以对其进行校验:

public class IDCardValidate
{
   public static boolean validate(String no)
   {
      // 对身份证号进行长度等简单判断
      if (no == null || no.length() != 18 || !no.matches("\\d{17}[0-9X]"))
      {
         return false;
      }
      // 1-17位相乘因子数组
      int[] factor = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
      // 18位随机码数组
      char[] random = "10X98765432".toCharArray();
      // 计算1-17位与相应因子乘积之和
      int total = 0;
      for (int i = 0; i < 17; i++)
      {
         total += Character.getNumericValue(no.charAt(i)) * factor[i];
      }
      // 判断随机码是否相等
      return random[total % 11] == no.charAt(17);
   }

   public static void main(String[] args)
   {
      // 正确
      System.out.println(validate("432831196411150810"));
      // 错误
      System.out.println(validate("432831196411150813"));
   }
}

2018年04约13日添加

上面的验证是提供了一个思路,对二代身份证号码进行了验证,下面补充一个相对全一些示例,可以实现一代与二代身份证号码的校验,并提供了二代身份证号码之间的转换。代码如下:

package com.jianggujin.messagequery;

import java.util.regex.Pattern;

/**
 * 身份证号码规则:<br/>
 * 第一代身份证:<br/>
 * 1-2:所在省(直辖市、自治区)的代码<br/>
 * 3-4:所在地级市(自治州)的代码<br/>
 * 5-6:所在区(县、自治县、县级市)的代码<br/>
 * 7-12:出生年(两位)、月、日<br/>
 * 13-14:所在地的派出所的代码<br/>
 * 15:奇数表示男性,偶数表示女性<br/>
 * 第二代身份证:<br/>
 * 1-2:所在省(直辖市、自治区)的代码<br/>
 * 3-4:所在地级市(自治州)的代码<br/>
 * 5-6:所在区(县、自治县、县级市)的代码<br/>
 * 7-14:出生年、月、日<br/>
 * 15-16:所在地的派出所的代码<br/>
 * 17:奇数表示男性,偶数表示女性<br/>
 * 18:也有的说是个人信息码,不是随计算机的随机产生,它是 用来检验身份证的正确性。校检码可以是0-9的数字,有时也用X表示。
 * 
 * @author jianggujin
 *
 */
public class JIdCardUtils {
   private final static Pattern PARTTERN_CARD_NO = Pattern.compile("\\d{15}|\\d{17}[0-9X]");
   private final static Pattern PARTTERN_DATE = Pattern.compile(
         "(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})(((0[13578]|1[02])(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)(0[1-9]|[12][0-9]|30))|(02(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))0229)");
   // 1-17位相乘因子数组
   private final static int[] FACTOR = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
   // 18位随机码数组
   private final static char[] RANDOM = "10X98765432".toCharArray();

   public boolean validate(String idCardNo) {
      // 对身份证号进行长度等简单判断
      if (idCardNo == null || !PARTTERN_CARD_NO.matcher(idCardNo).matches()) {
         return false;
      }
      int len = idCardNo.length();
      // 一代身份证
      if (len == 15) {
         return PARTTERN_DATE.matcher("19" + idCardNo.substring(6, 12)).matches();
      }
      // 二代身份证
      if (len == 18 && PARTTERN_DATE.matcher(idCardNo.substring(6, 14)).matches()) {
         // 判断随机码是否相等
         return calculateRandom(idCardNo) == idCardNo.charAt(17);
      } else {
         return false;
      }

   }

   /**
    * 计算最后一位随机码
    * 
    * @param idCardNo
    * @return
    */
   private char calculateRandom(String idCardNo) {
      // 计算1-17位与相应因子乘积之和
      int total = 0;
      for (int i = 0; i < 17; i++) {
         total += Character.getNumericValue(idCardNo.charAt(i)) * FACTOR[i];
      }
      // 判断随机码是否相等
      return RANDOM[total % 11];
   }

   /**
    * 计算最后一位随机码
    * 
    * @param idCardNo
    * @return
    */
   private char calculateRandom(char[] idCardNo) {
      // 计算1-17位与相应因子乘积之和
      int total = 0;
      for (int i = 0; i < 17; i++) {
         total += Character.getNumericValue(idCardNo[i]) * FACTOR[i];
      }
      // 判断随机码是否相等
      return RANDOM[total % 11];
   }

   /**
    * 15和18位身份证号码转换
    * 
    * @param idCardNo
    * @return
    */
   public String convert(String idCardNo) {
      if (idCardNo == null) {
         throw new IllegalArgumentException("idCardNo must not null.");
      }
      if (!validate(idCardNo)) {
         throw new IllegalArgumentException("idCardNo invalid.");
      }
      int len = idCardNo.length();
      char[] result = null;
      int index = 0;
      if (len == 15) {// 添加年份与随机码
         result = new char[18];
         // 复制行政区域代码
         for (; index < 6; index++) {
            result[index] = idCardNo.charAt(index);
         }
         // 添加年份,固定值:19
         result[index++] = '1';
         result[index++] = '9';
         // 添加年月日与附加信息
         for (; index < 17; index++) {
            result[index] = idCardNo.charAt(index - 2);
         }
         result[index] = calculateRandom(result);
      } else if (len == 18) {// 去除年份与随机码
         result = new char[15];
         // 复制行政区域代码
         for (; index < 6; index++) {
            result[index] = idCardNo.charAt(index);
         }
         // 跳过两位年份;
         index += 2;
         // 去除最后一位
         for (; index < 17; index++) {
            result[index - 2] = idCardNo.charAt(index);
         }
      }
      if (result == null) {
         throw new IllegalArgumentException("idCardNo length must equals 15 or 18.");
      }
      return new String(result);
   }
}

需要注意的是上面的代码并没有校验行政区域代码的有效性,仅仅校验了是否为6位数字,如果想要校验行政区域代码,可以查询公共信息判断代码是否合法。

文章最后发布于: 2016-06-22 11:26:16
展开阅读全文
0 个人打赏

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览