Browse Source

添加港澳台身份证的校验

lighter 2 years ago
parent
commit
e7d0b3e0af
1 changed files with 140 additions and 5 deletions
  1. 140 5
      src/main/java/thyyxxk/webserver/utils/IdCardUtil.java

+ 140 - 5
src/main/java/thyyxxk/webserver/utils/IdCardUtil.java

@@ -6,6 +6,8 @@ import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * @description: IdCard functions
@@ -20,6 +22,48 @@ public class IdCardUtil {
     private static final int[] POWER = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
     private static final int MAX_LENGTH = 18;
     private static final int MIN_LENGTH = 15;
+    /** 台湾身份首字母对应数字 */
+    public static Map<String, Integer> twFirstCode = new HashMap<>();
+    /** 香港身份首字母对应数字 */
+    public static Map<String, Integer> hkFirstCode = new HashMap<>();
+    static {
+        twFirstCode.put("A", 10);
+        twFirstCode.put("B", 11);
+        twFirstCode.put("C", 12);
+        twFirstCode.put("D", 13);
+        twFirstCode.put("E", 14);
+        twFirstCode.put("F", 15);
+        twFirstCode.put("G", 16);
+        twFirstCode.put("H", 17);
+        twFirstCode.put("J", 18);
+        twFirstCode.put("K", 19);
+        twFirstCode.put("L", 20);
+        twFirstCode.put("M", 21);
+        twFirstCode.put("N", 22);
+        twFirstCode.put("P", 23);
+        twFirstCode.put("Q", 24);
+        twFirstCode.put("R", 25);
+        twFirstCode.put("S", 26);
+        twFirstCode.put("T", 27);
+        twFirstCode.put("U", 28);
+        twFirstCode.put("V", 29);
+        twFirstCode.put("X", 30);
+        twFirstCode.put("Y", 31);
+        twFirstCode.put("W", 32);
+        twFirstCode.put("Z", 33);
+        twFirstCode.put("I", 34);
+        twFirstCode.put("O", 35);
+        hkFirstCode.put("A", 1);
+        hkFirstCode.put("B", 2);
+        hkFirstCode.put("C", 3);
+        hkFirstCode.put("R", 18);
+        hkFirstCode.put("U", 21);
+        hkFirstCode.put("Z", 26);
+        hkFirstCode.put("X", 24);
+        hkFirstCode.put("W", 23);
+        hkFirstCode.put("O", 15);
+        hkFirstCode.put("N", 14);
+    }
 
     /**
      * 验证所有的身份证的合法性
@@ -34,13 +78,10 @@ public class IdCardUtil {
         if (StringUtil.isBlank(idCard)) {
             return false;
         }
-        if (idCard.startsWith("R")) {
-            return true;
-        }
-        return isValidate18IdCard(idCard);
+        return validateIdCard18(idCard) || validateIdCard10(idCard);
     }
 
-    private static boolean isValidate18IdCard(String idCard) {
+    private static boolean validateIdCard18(String idCard) {
         // 非18位为假
         if (idCard.length() != MAX_LENGTH) {
             return false;
@@ -230,4 +271,98 @@ public class IdCardUtil {
         }
         return --age;
     }
+
+    /**
+     * 验证10位身份证编码是否合法
+     */
+    private static boolean validateIdCard10(String idCard) {
+        String card = idCard.replaceAll("\\(", "").replaceAll("\\)", "");
+        if (card.length() != 8 && card.length() != 9 && idCard.length() != 10) {
+            return false;
+        }
+        if (idCard.matches("^[A-Z]{1,2}[0-9]{6}\\(?[0-9A]\\)?$")) { // 香港
+            return validateHKCard(idCard);
+        }
+        if (idCard.matches("^[1|5|7][0-9]{6}\\(?[0-9A-Z]\\)?$")) { // 澳门,目前没做校验,澳门的直接返回true
+            return true;
+        }
+        if (idCard.matches("^[a-zA-Z][0-9]{9}")) { // 台湾
+            String char2 = idCard.substring(1, 2);
+            if (!char2.equals("1") && !char2.equals("2")) {
+                return false;
+            }
+            return validateTWCard(idCard);
+        }
+        return false;
+    }
+
+    /**
+     * 验证台湾身份证号码
+     * 共10位
+     * 计算校验码的步骤:1、英文转成数字,其个位数字*9+十位数
+     *         2、中间八位数字,各数字从左到右依次乘以8、7、6、5....2、1
+     *         3、计算步骤1和2的和sum
+     *         4、计算10-sum%10 ,其结果就是检查码,若余数为0,则检查码就是0
+     * @param idCard
+     *            身份证号码
+     * @return 验证码是否符合
+     */
+    private static boolean validateTWCard(String idCard) {
+        //第一位是字母(表示地区代码),通过map找到对应的数字代码
+        String start = idCard.substring(0, 1);
+        //第二位数字表示性别,男生为1,女生为2
+        String mid = idCard.substring(1, 9);
+        //最后一位是检查码,由第一位和8个数字的组合计算得到校验和
+        String end = idCard.substring(9, 10);
+        Integer iStart = twFirstCode.get(start);
+
+        int sum = iStart / 10 + (iStart % 10) * 9;
+        char[] chars = mid.toCharArray();
+        int iflag = 8;
+        for (char c : chars) {
+            sum = sum + Integer.parseInt(c + "") * iflag;
+            iflag--;
+        }
+        return (sum % 10 == 0 ? 0 : (10 - sum % 10)) == Integer.parseInt(end);
+    }
+
+    /**
+     * 验证香港身份证号码(存在Bug,部份特殊身份证无法检查)
+     *
+     * 如:身份证号码是:C668668(9)
+     * 香港身份证号码由三部分组成:一个英文字母;6个数字;括号及0-9中的任一个数字,或者字母A。
+     * 括号中的数字或字母A,是校验码,用于检验括号前面的号码的逻辑正确性。
+     *
+     * 身份证前2位为英文字符,如果只出现一个英文字符则表示第一位是空格,对应数字58, 前2位英文字符A-Z分别对应数字10-35
+     * 最后一位校验码为0-9的数字加上字符"A","A"代表10
+     * 将身份证号码全部转换为数字,分别对应乘9、8...1相加的总和,整除11则证件号码有效
+     *
+     * @param idCard
+     *            身份证号码
+     * @return 验证码是否符合
+     */
+    private static boolean validateHKCard(String idCard) {
+        String card = idCard.replaceAll("\\(", "").replaceAll("\\)", "");
+        int sum = 0;
+        if (card.length() == 9) {
+            sum = ((int) card.charAt(0) - 55) * 9 + ((int) card.charAt(1) - 55) * 8;
+            card = card.substring(1, 9);
+        } else {
+            sum = 522 + ((int) card.charAt(0) - 55) * 8;
+        }
+        String mid = card.substring(1, 7);
+        String end = card.substring(7, 8);
+        char[] chars = mid.toCharArray();
+        int iflag = 7;
+        for (char c : chars) {
+            sum = sum + Integer.parseInt(c + "") * iflag;
+            iflag--;
+        }
+        if (end.equalsIgnoreCase("A")) {
+            sum = sum + 10;
+        } else {
+            sum = sum + Integer.parseInt(end);
+        }
+        return sum % 11 == 0;
+    }
 }