1. 程式人生 > >Java 身份證驗證及獲取出生日期、性別

Java 身份證驗證及獲取出生日期、性別

廢話不多說,直接上程式碼,程式碼很簡單,不多說廢話了

package com.ngupcc.commons.util;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Pattern;

/**
 * 身份證工具類,由於現在使用的是二代身份證,所以只驗證18位<br>
 * 身份證號碼中涉及到行政區劃程式碼,程式碼不能驗證其是否真實存在,所以我們只能驗證身份號碼邏輯正確性,
 * 並不能驗證身份證號碼是否真實存在<br>
 *
 *  ①地址碼:(前6位)所在縣(市、旗、區)的行政區劃程式碼
 *  ②出生日期碼:(第7位到第14位)
 *  ③順序碼:(第15位到17位)縣、區級政府所轄派出所的分配碼
 *  ④校驗碼:(最後1位)
 * @autor zhouqibing
 * @time 2018-01-13 21:29
 **/
public class IDCardUtils {
    // 正則格式
    private static Pattern pattern = Pattern.compile("^\\d{17}[\\d|X]$");

    /**
     * 省、直轄市程式碼表,身份證號的前6位為地址資訊,我們只驗證前兩位
     */
    private static final String CITY_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 static final int POWER[] = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

    /**
     * 第18位校檢碼
     **/
    private static final String VERIFY_CODE[] = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};

    /**
     * 驗證身份證
     * @param idno
     * @return
     */
    public static boolean verify(String idno){
        //1.格式驗證
        if(idno == null || !pattern.matcher(idno = idno.toUpperCase()).matches()){
            return false;
        }

        //2.驗證省、直轄市程式碼。市、區不作驗證,沒有規則限制,數字即可
        if(Arrays.binarySearch(CITY_CODE, idno.substring(0, 2)) == -1){
            return false;
        }

        //3.驗證生日,生日可能存在輸入20180231這種情況,所以使用Calendar處理校驗
        String birthday = idno.substring(6, 14);
        // 如果輸入的日期為20180231,通過轉換的後realBirthday為20180303
        Date realBirthday = toBirthDay(birthday);
        // 轉換失敗或不相等
        if(realBirthday == null || !birthday.equals(new SimpleDateFormat("yyyyMMdd").format(realBirthday))){
            return false;
        }

        //4.順序碼不作驗證,沒有規則限制,數字即可
        //5.驗證位驗證,計算規則為:身份證前17位數字,對應乘以每位的權重因子,然後相加得到數值X,與11取模獲得餘數,得到數值Y,通過Y得到校驗碼。
        String verifyCode = VERIFY_CODE[getPowerSum(idno) % 11];
        if(!verifyCode.equals(idno.substring(17, 18))){
            return false;
        }
        return true;
    }

    /**
     * 取得身份證號前17位與對應的權重值相乘的和
     * @return
     */
    private static int getPowerSum(String idno){
        int sum = 0;
        // 身份證前17位
        char[] fix17 = idno.substring(0, 17).toCharArray();
        for(int i = 0 ; i <= 16 ; i++){
            sum += (Integer.parseInt(fix17[i] + "") * POWER[i]);
        }
        return sum;
    }

    /**
     * 轉換成日期
     * @param birthday
     * @return
     */
    private static Date toBirthDay(String birthday){
        try{
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.YEAR, Integer.parseInt(birthday.substring(0, 4)));
            calendar.set(Calendar.MONTH, Integer.parseInt(birthday.substring(4, 6)) - 1);//月份從0開始,所以減1
            calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(birthday.substring(6, 8)));
            //以下設定意義不大
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);

            return calendar.getTime();
        }catch (Exception e){
            return null;
        }
    }
    /**
     * 從身份證號碼中獲取生日
     * @param idno
     * @return null表示idno錯誤,未獲取到生日
     */
    public static Date getBirthDay(String idno){
        if(!verify(idno)){
            return null;
        }

        return toBirthDay(idno.substring(6, 14));
    }

    /**
     * 從身份證號中獲取性別
     * @param idno
     * @return 0:獲取失敗,1:男,2:女
     */
    public static int getGender(String idno){
        if(!verify(idno)){
            return 0;
        }
        // 奇男,偶女
        return (Integer.parseInt(idno.substring(16, 17)) % 2) == 0 ? 2 : 1;
    }
}