好用的IdCardNumberMethod工具類(直接複製使用)

阿迪di發表於2024-07-09
package com.examine.ythgk.util;

import com.examine.common.core.utils.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created with IntelliJ IDEA.
 * User: Shendi
 * Date: 2022/12/4/004
 * Time: 17:04
 * Description:從身份證號碼中獲取出生日期、性別、年齡(15位和18位)
 */
public class IdCardNumberMethod {

    /**
     * 校驗車牌號是否正確
     */
    public static boolean checkPlateNumber(String clcph){
        // 中國車牌號規則正規表示式,允許6或7位字元
        String pattern = "(^[京津滬渝冀豫雲遼黑湘皖魯新蘇浙贛鄂桂甘晉蒙陝吉閩貴粵青藏川寧瓊使領A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9掛學警港澳E]{1}[A-Z0-9]{1}$)|(^[京津滬渝冀豫雲遼黑湘皖魯新蘇浙贛鄂桂甘晉蒙陝吉閩貴粵青藏川寧瓊使領A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9掛學警港澳]{1}$)";
        // 編譯正規表示式
        Pattern p = Pattern.compile(pattern);
        // 進行匹配
        Matcher m = p.matcher(clcph);
        // 返回匹配結果
        return m.matches();
    }

    /**
     * 獲取出生日期
     *
     * @return 返回字串型別
     */
    public String getBirthFromIdCard(String idCard) {
        if (idCard.length() != 18 && idCard.length() != 15) {
            return "請輸入正確的身份證號碼";
        }
        if (idCard.length() == 18) {
            String year = idCard.substring(6).substring(0, 4);// 得到年份
            String month = idCard.substring(10).substring(0, 2);// 得到月份
            String day = idCard.substring(12).substring(0, 2);// 得到日
            return (year + "-" + month + "-" + day);
        } else if (idCard.length() == 15) {
            String year = "19" + idCard.substring(6, 8);// 年份
            String month = idCard.substring(8, 10);// 月份
            String day = idCard.substring(10, 12);// 得到日
            return (year + "-" + month + "-" + day);
        }
        return null;
    }

    /**
     * 獲取出生日期
     *
     * @return 返回日期格式
     */
    public Date getBirthDayFromIdCard(String idCard) throws ParseException {
        Date birth = null;
        if (idCard.length() == 18) {
            String year = idCard.substring(6).substring(0, 4);// 得到年份
            String month = idCard.substring(10).substring(0, 2);// 得到月份
            String day = idCard.substring(12).substring(0, 2);// 得到日
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            birth = format.parse(year + "-" + month + "-" + day);
        } else if (idCard.length() == 15) {
            String year = "19" + idCard.substring(6, 8);// 年份
            String month = idCard.substring(8, 10);// 月份
            String day = idCard.substring(10, 12);// 得到日
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            birth = format.parse(year + "-" + month + "-" + day);
        }
        return birth;
    }

    /**
     * 獲取性別
     *        0=未知的性別,9=未說明的性別,2=女性,1=男性
     * @return int
     */
    public static int getSexFromIdCard(String idCard) {
        int sex = 9;
        // 身份證號碼為空
        if (idCard == "" || idCard.length() <= 0){
            return sex = 0;
        }
        if (idCard.length() == 18) {
            if (Integer.parseInt(idCard.substring(16).substring(0, 1)) % 2 == 0) {// 判斷性別
                sex = 2; //
            } else {
                sex = 1; //
            }
        } else if (idCard.length() == 15) {
            String usex = idCard.substring(14, 15);// 使用者的性別
            if (Integer.parseInt(usex) % 2 == 0) {
                sex = 2; //
            } else {
                sex = 1; //
            }
        }
        return sex;
    }
    /**
     * 獲取性別
     *        0=未知的性別,9=未說明的性別,2=女性,1=男性
     * @return int
     */
    public static String getSexFromIdCardXbmc(String idCard) {
        String sex = "未說明的性別";
        // 身份證號碼為空
        if (idCard == "" || idCard.length() <= 0){
            return sex = "未知的性別";
        }
        if (idCard.length() == 18) {
            if (Integer.parseInt(idCard.substring(16).substring(0, 1)) % 2 == 0) {// 判斷性別
                sex = "女"; //
            } else {
                sex = "男"; //
            }
        } else if (idCard.length() == 15) {
            String usex = idCard.substring(14, 15);// 使用者的性別
            if (Integer.parseInt(usex) % 2 == 0) {
                sex = "女"; //
            } else {
                sex = "男"; //
            }
        }
        return sex;
    }

    /**
     * 根據身份證的號碼算出當前身份證持有者的年齡
     *
     * @param
     * @throws Exception
     * @return  -1(表示異常) 0 (身份證號碼為空)
     */
    public static int getAgeForIdcard(String idcard) {
        try {
            int age = 0;
            if (StringUtils.isEmpty(idcard)) {
                return age;
            }

            String birth = "";
            if (idcard.length() == 18) {
                birth = idcard.substring(6, 14);
            } else if (idcard.length() == 15) {
                birth = "19" + idcard.substring(6, 12);
            }

            int year = Integer.valueOf(birth.substring(0, 4));
            int month = Integer.valueOf(birth.substring(4, 6));
            int day = Integer.valueOf(birth.substring(6));
            Calendar cal = Calendar.getInstance();
            age = cal.get(Calendar.YEAR) - year;
            //週歲計算
            if (cal.get(Calendar.MONTH) < (month - 1) || (cal.get(Calendar.MONTH) == (month - 1) && cal.get(Calendar.DATE) < day)) {
                age--;
            }
            return age;
        } catch (Exception e) {
            e.getMessage();
        }
        return -1;
    }

    /**
     * 15 位身份證號碼轉 18 位
     * <p>
     * 15位身份證號碼:第7、8位為出生年份(兩位數),第9、10位為出生月份,第11、12位代表出生日期,第15位代表性別,奇數為男,偶數為女。
     * 18位身份證號碼:第7、8、9、10位為出生年份(四位數),第11、第12位為出生月份,第13、14位代表出生日期,第17位代表性別,奇數為男,偶數為女。
     */
    public StringBuffer IdCardMethod15To18(String idCard) {
        //將字串轉化為buffer進行操作
        StringBuffer stringBuffer = new StringBuffer(idCard);
        //身份證最後一位校驗碼,X代表10(順序固定)
        char[] checkIndex = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
        int sum = 0;
        //在第6位插入年份的前兩位19
        stringBuffer.insert(6, "19");
        for (int i = 0; i < stringBuffer.length(); i++) {
            char c = stringBuffer.charAt(i);
            //前17位數字
            int ai = Integer.valueOf(String.valueOf(c));
            //前17位每位對應的係數(7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 )
            int wi = ((int) Math.pow(2, stringBuffer.length() - i)) % 11;
            //總和(每位數字乘以係數再相加)
            sum = sum + ai * wi;
        }
        //總和除以11求餘
        int indexOf = sum % 11;
        //根據餘數作為下表在校驗碼陣列裡取值
        stringBuffer.append(checkIndex[indexOf]);
        return stringBuffer;
    }

    /** 以下是對身份證號碼驗證內容 **/
    /** 省份開頭字典 */
    private static Map<Integer, String> provinces = new HashMap<>();
    static {
        provinces.put(11, "北京");
        provinces.put(12, "天津");
        provinces.put(13, "河北");
        provinces.put(14, "山西");
        provinces.put(15, "內蒙古");
        provinces.put(21, "遼寧");
        provinces.put(22, "吉林");
        provinces.put(23, "黑龍江");
        provinces.put(31, "上海");
        provinces.put(32, "江蘇");
        provinces.put(33, "浙江");
        provinces.put(34, "安徽");
        provinces.put(35, "福建");
        provinces.put(36, "江西");
        provinces.put(37, "山東");
        provinces.put(41, "河南");
        provinces.put(42, "湖北 ");
        provinces.put(43, "湖南");
        provinces.put(44, "廣東");
        provinces.put(45, "廣西");
        provinces.put(46, "海南");
        provinces.put(50, "重慶");
        provinces.put(51, "四川");
        provinces.put(52, "貴州");
        provinces.put(53, "雲南");
        provinces.put(54, "西藏 ");
        provinces.put(61, "陝西");
        provinces.put(62, "甘肅");
        provinces.put(63, "青海");
        provinces.put(64, "寧夏");
        provinces.put(65, "新疆");
        provinces.put(71, "臺灣");
        provinces.put(81, "香港");
        provinces.put(82, "澳門");
    }

    /**
     * @description 簡單校驗滿足非空及18位,無法校驗到月份對應天數
     * @date 2022/10/10 16:52
     * @param
     * @param IdCard
     * @return boolean
     */
    public static boolean easyCheckIdCard(String IdCard) {
        //字串為空或者不符合簡單的18位校驗返回false
        String regex = "^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$";
        if (StringUtils.isBlank(IdCard) || !Pattern.matches(regex, IdCard)) {
            return false;
        }
        return true;
    }


    /**
     * @description 中級校驗,不校驗最後一位
     * @date 2022/10/10 16:57
     * @param
     * @param IdCard
     * @return boolean
     */
    public static boolean middleCheckIdCard(String IdCard) {
        return (easyCheckIdCard(IdCard) && checkBirthday(IdCard) && checkProvince(IdCard));
    }

    /**
     * @description 高階校驗包含校驗位
     * @date 2022/10/10 16:57
     * @param
     * @param IdCard
     * @return boolean
     */
    public static boolean highCheckIdCard(String IdCard) {
        return (middleCheckIdCard(IdCard) && checkLastNumber(IdCard));
    }

    /**
     * @description 身份證校驗位的校驗
     * @date 2022/10/10 15:16
     * @param
     * @param IdCard
     * @return boolean
     */
    public static boolean checkLastNumber(String IdCard) {
        try {
            char[] charArray = IdCard.toCharArray();
            //前十七位加權因子
            int[] IdCardWi = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
            //這是除以11後,可能產生的11位餘數對應的驗證碼
            String[] IdCardY = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
            int sum = 0;
            for (int i = 0; i < IdCardWi.length; i++) {
                int current = Integer.parseInt(String.valueOf(charArray[i]));
                int count = current * IdCardWi[i];
                sum += count;
            }
            char IdCardLast = charArray[17];
            int IdCardMod = sum % 11;
            return IdCardY[IdCardMod].toUpperCase().equals(String.valueOf(IdCardLast).toUpperCase());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * @description 年月日校驗
     * @date 2022/10/10 16:48
     * @param
     * @param IdCard
     * @return boolean
     */
    public static boolean checkBirthday(String IdCard) {
        String yearRegex = "(18|19|20)\\d{2}";
        String monthRegex = "(0[1-9])|10|11|12";
        String dayRegex = "([0-2][1-9])|10|20|30|31";
        String year = IdCard.substring(6, 10);
        if (!Pattern.matches(yearRegex, year)) {
            return false;
        }
        String month = IdCard.substring(10, 12);
        if (!Pattern.matches(monthRegex, month)) {
            return false;
        }
        String day = IdCard.substring(12, 14);
        if (!Pattern.matches(dayRegex, day)) {
            return false;
        }
        Integer yearInt = Integer.parseInt(year);
        Integer monthInt = Integer.parseInt(month);
        Integer dayInt = Integer.parseInt(day);
        switch (monthInt) {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                return true;
            case 2:
                if (leapYear(yearInt)) {
                    //閏年 29
                    return dayInt <= 29;
                }
                return dayInt <= 28;
            default:
                return dayInt <= 30;
        }
    }

    /**
     * @description 校驗是否為閏年
     * @date 2022/10/10 15:39
     * @param
     * @param year
     * @return boolean
     */
    public static boolean leapYear(int year) {
        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
            return true;
        }
        return false;
    }

    /**
     * @description 身份證省份的校驗,這裡預設符合簡單的18位校驗
     * @date 2022/10/10 15:18
     * @param
     * @param IdCard
     * @return boolean
     */
    public static boolean checkProvince(String IdCard) {
        String pattern = "^[1-9][0-9]";
        String prov = IdCard.substring(0, 2);
        if (Pattern.matches(pattern, prov)) {
            return provinces.containsKey(Integer.parseInt(prov));
        }
        return false;
    }

}

相關文章