中国15_18位身份证号码校验工具类

Java常用方法   2025-01-12 15:18   251   0  

一、身份证号码工具类

package com.chenwc.tools;

import java.time.LocalDate;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 中国身份证号码工具类
 *
 * @author chenwc
 * @date 2023/3/1 20:28
 */
public class IdCard {

    /**
     * 18位身份证正则表达式
     */
    private final static String ID_18 = "^[1-9][0-9]{5}(18|19|20)[0-9]{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)[0-9]{3}([0-9]|(X|x))";
    /**
     * 15位身份证正则表达式
     */
    private final static String ID_15 = "^[1-9][0-9]{5}[0-9]{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)[0-9]{2}[0-9]";

    /**
     * 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X。
     */
    private final static String ID_PATTERN = "(^\\d{15}$)|(^\\d{17}([0-9]|X)$)";

    /**
     * 校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
     * 前17位数字相乘的系数
     */
    private final static Integer[] arrInt = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
    /**
     * 校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
     * 对17位数字和系数相乘的结果相加,用加出来和除以11,余数
     */
    private final static Character[] arrCh = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};

    /**
     * 省份列表
     */
    private final static Map<Integer, String> provinceMap = new HashMap<Integer, String>() {{
        put(11, "北京市");
        put(12, "天津市");
        put(13, "河北省");
        put(14, "山西省");
        put(15, "内蒙古自治区");
        put(21, "辽宁省");
        put(22, "吉林省");
        put(23, "黑龙江省");
        put(31, "上海市");
        put(32, "江苏省");
        put(33, "浙江省");
        put(34, "安徽省");
        put(35, "福建省");
        put(36, "江西省");
        put(37, "山东省");
        put(41, "河南省");
        put(42, "湖北省");
        put(43, "湖南省");
        put(44, "广东省");
        put(45, "广西壮族自治区");
        put(46, "海南省");
        put(50, "重庆市");
        put(51, "四川省");
        put(52, "贵州省");
        put(53, "云南省");
        put(54, "西藏自治区");
        put(61, "陕西省");
        put(62, "甘肃省");
        put(63, "青海省");
        put(64, "宁夏回族自治区");
        put(65, "新疆维吾尔自治区");
        put(71, "台湾省");
        put(81, "香港特别行政区");
        put(82, "澳门特别行政区");
        put(91, "国外");
    }};

    /**
     * 判断是否符合身份证格式,身份证号(15位号码应全为数字,18位号码末位可以为数字或X)
     *
     * @param idCard 身份证号码字符串
     * @return 符合返回true,不符合返回false
     */
    public static boolean isIdCardNums(String idCard) {
        if (null == idCard || idCard.isEmpty()) {
            return false;
        }
        if (idCard.length() == 15) {
            Pattern pattern = Pattern.compile(ID_15);
            Matcher matcher = pattern.matcher(idCard);
            return matcher.matches();
        }
        if (idCard.length() == 18) {
            Pattern pattern = Pattern.compile(ID_18);
            Matcher matcher = pattern.matcher(idCard);
            return matcher.matches();
        }
        return false;
    }

    /**
     * 把15位身份证转成18位
     *
     * @param IdCard_15 15位身份证
     * @return 18位身份证
     */
    public static String change15To18IdCard(String IdCard_15) {
        int len = IdCard_15.length();
        Pattern pattern = Pattern.compile(ID_PATTERN);
        Matcher matcher = pattern.matcher(IdCard_15);
        if (!matcher.matches()) {
            throw new RuntimeException("输入的身份证号长度不对,或者号码不符合规定!15位号码应全为数字。");
        }
        if (len == 15) {
            List<String> numList = new ArrayList<>();
            numList.add(IdCard_15.substring(0, 6));
            numList.add(IdCard_15.substring(6, 8));
            numList.add(IdCard_15.substring(8, 10));
            numList.add(IdCard_15.substring(10, 12));
            numList.add(IdCard_15.substring(12));

            if (!isBirthDayInValid(numList)) {
                //将15位身份证转成18位
                int nTemp = 0, i;
                String IdCard_18;
                IdCard_18 = IdCard_15.substring(0, 6) + "19" + IdCard_15.substring(6);
                for (i = 0; i < 17; i++) {
                    nTemp = nTemp + Integer.parseInt(String.valueOf(IdCard_18.charAt(i))) * arrInt[i];
                }
                IdCard_18 += arrCh[nTemp % 11];
                return IdCard_18;
            }
        }
        return null;
    }

    /**
     * 验证15位和18位的身份证,并且包含生日和校验位的验证。
     *
     * @param num 身份证号码
     * @return 符合返回true,不符合返回false
     */
    public static boolean isIdCardNo(String num) {
        num = num.toUpperCase();

        Pattern pattern = Pattern.compile(ID_PATTERN);
        Matcher matcher = pattern.matcher(num);
        if (!matcher.matches()) {
            throw new RuntimeException("输入的身份证号长度不对,或者号码不符合规定!15位号码应全为数字,18位号码末位可以为数字或X。");
        }
        int province = Integer.parseInt(num.substring(0, 2));
        if (!provinceMap.containsKey(province)) {
            throw new RuntimeException("非法地区:" + province);
        }
        //下面分别分析出生日期和校验位
        int len = num.length();
        if (len == 15) {
            List<String> numList = new ArrayList<>();
            numList.add(num.substring(0, 6));
            numList.add(num.substring(6, 8));
            numList.add(num.substring(8, 10));
            numList.add(num.substring(10, 12));
            numList.add(num.substring(12));

            return !isBirthDayInValid(numList);
        }
        if (len == 18) {
            List<String> numList = new ArrayList<>();
            numList.add(num.substring(0, 6));
            numList.add(num.substring(6, 10));
            numList.add(num.substring(10, 12));
            numList.add(num.substring(12, 14));
            numList.add(num.substring(14));

            if (isBirthDayInValid(numList)) {
                return false;
            } else {
                //检验18位身份证的校验码是否正确。
                char valnum;
                int nTemp = 0, i;
                for (i = 0; i < 17; i++) {
                    nTemp = nTemp + Integer.parseInt(String.valueOf(num.charAt(i))) * arrInt[i];
                }
                valnum = arrCh[nTemp % 11];
                if (!String.valueOf(valnum).equals(num.substring(17))) {
                    throw new RuntimeException("18位身份证的校验码不正确!应该为:" + valnum);
                }
                return true;
            }
        }
        return false;
    }

    /**
     * 校验出生日期是否合法
     *
     * @param numList 出生日期
     * @return 不合法返回true,合法返回false
     */
    private static boolean isBirthDayInValid(List<String> numList) {
        int year;
        if (numList.get(1).length() == 2) {
            year = Integer.parseInt("19" + numList.get(1));
        } else {
            year = Integer.parseInt(numList.get(1));
        }
        int date = Integer.parseInt(numList.get(3));
        int month = Integer.parseInt(numList.get(2));
        if (year < 1900 || year > 2099) {
            throw new RuntimeException("输入的身份证号里出生日期不对: " + year + "年" + month + "月" + date + "日");
        }
        if (month <= 0 || month > 12) {
            throw new RuntimeException("输入的身份证号里出生日期不对: " + year + "年" + month + "月" + date + "日");
        }
        if (date <= 0) {
            throw new RuntimeException("输入的身份证号里出生日期不对: " + year + "年" + month + "月" + date + "日");
        }
        if (2 == month) {
            LocalDate localDate;
            if (numList.get(1).length() == 2) {
                localDate = LocalDate.parse("19" + numList.get(1) + "-01-01");
            } else {
                localDate = LocalDate.parse(numList.get(1) + "-01-01");
            }
            //闰年
            if (localDate.isLeapYear()) {
                if (date > 29) {
                    throw new RuntimeException("输入的身份证号里出生日期不对,闰年2月只有29天: " + year + "年" + month + "月" + date + "日");
                }
            } else {
                if (date > 28) {
                    throw new RuntimeException("输入的身份证号里出生日期不对,非闰年2月只有28天: " + year + "年" + month + "月" + date + "日");
                }
            }
        } else {
            if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
                if (date > 31) {
                    throw new RuntimeException("输入的身份证号里出生日期不对," + month + "月只有31天: " + year + "年" + month + "月" + date + "日");
                }
            } else {
                if (date > 30) {
                    throw new RuntimeException("输入的身份证号里出生日期不对," + month + "月只有30天: " + year + "年" + month + "月" + date + "日");
                }
            }
        }
        return false;
    }

    /**
     * 生成随机的18位身份证号码
     * 出生日期为:1900-01-01 ~ 今天
     *
     * @return 18位身份证号码
     */
    public static String generateRandom18IdCard() {
        StringBuilder stringBuilder = new StringBuilder();
        List<Integer> list = new ArrayList<>(provinceMap.keySet());
        //生成前6位地区数字
        stringBuilder.append(list.get(RandomUuid.getRandomIntByBound(list.size())));
        stringBuilder.append(RandomUuid.getRandomInt0To9());
        stringBuilder.append(RandomUuid.getRandomInt0To9());
        stringBuilder.append(RandomUuid.getRandomInt0To9());
        stringBuilder.append(RandomUuid.getRandomInt0To9());
        //年
        LocalDate today = LocalDate.now();
        String[] year = {"19", "20"};
        String yearStr;
        String addYearStr = year[RandomUuid.getRandomIntByBound(year.length)];
        stringBuilder.append(addYearStr);
        int lastYear;
        int yearBound = 99;
        if (!"19".equals(addYearStr)) {
            //获取今年的年+1
            yearBound = Integer.parseInt(String.valueOf(today.getYear() + 1).substring(2));
        }
        lastYear = RandomUuid.getRandomIntByBound(yearBound);
        if (lastYear < 10) {
            stringBuilder.append("0").append(lastYear);
            yearStr = addYearStr + "0" + lastYear;
        } else {
            stringBuilder.append(lastYear);
            yearStr = addYearStr + lastYear;
        }
        //月
        int monthBound = 13;
        if (today.getYear() == Integer.parseInt(yearStr)) {
            monthBound = today.getMonthValue() + 1;
        }
        int month = RandomUuid.getRandomIntByBound(monthBound);
        while (month == 0) {
            month = RandomUuid.getRandomIntByBound(monthBound);
        }
        if (month < 10) {
            stringBuilder.append("0").append(month);
        } else {
            stringBuilder.append(month);
        }
        //日
        int date;
        if (2 == month) {
            LocalDate localDate = LocalDate.parse(yearStr + "-01-01");
            //闰年
            int dayBound;
            if (localDate.isLeapYear()) {
                dayBound = 30;
            }
            //非闰年
            else {
                dayBound = 29;
            }
            if (today.getYear() == Integer.parseInt(yearStr) && month == today.getMonthValue()) {
                dayBound = today.getDayOfMonth() + 1;
            }
            date = RandomUuid.getRandomIntByBound(dayBound);
            while (date == 0) {
                date = RandomUuid.getRandomIntByBound(dayBound);
            }
        }
        //大月31日
        else if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
            int dayBound = 32;
            if (today.getYear() == Integer.parseInt(yearStr) && month == today.getMonthValue()) {
                dayBound = today.getDayOfMonth() + 1;
            }
            date = RandomUuid.getRandomIntByBound(dayBound);
            while (date == 0) {
                date = RandomUuid.getRandomIntByBound(dayBound);
            }
        }
        //小月30日
        else {
            int dayBound = 31;
            if (today.getYear() == Integer.parseInt(yearStr) && month == today.getMonthValue()) {
                dayBound = today.getDayOfMonth() + 1;
            }
            date = RandomUuid.getRandomIntByBound(dayBound);
            while (date == 0) {
                date = RandomUuid.getRandomIntByBound(dayBound);
            }
        }
        if (date < 10) {
            stringBuilder.append("0").append(date);
        } else {
            stringBuilder.append(date);
        }
        //生成三位随机校验数字
        for (int i = 0; i < 3; i++) {
            stringBuilder.append(RandomUuid.getRandomInt0To9());
        }
        //计算校验和
        String num = stringBuilder.toString();
        int nTemp = 0, i;
        for (i = 0; i < 17; i++) {
            nTemp = nTemp + Integer.parseInt(String.valueOf(num.charAt(i))) * arrInt[i];
        }
        stringBuilder.append(arrCh[nTemp % 11]);
        return stringBuilder.toString();
    }
}

二、随机数工具类

package com.chenwc.tools;

import java.util.Random;

/**
 * 自定义随机数生成工具类
 *
 * @author chenwc
 * @date 2023/3/1 20:29
 */
public class RandomUuid {

    /**
     * 生成指定长度随机数UUID,包含0-9数字和字母(字母包含大小写)
     *
     * @param len 指定长度
     * @return 随机数UUID字符串
     */
    public static String getUuidByNumberAndCharacter(int len) {
        if (len <= 0) {
            throw new RuntimeException("长度要大于0");
        }
        StringBuilder val = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < len; i++) {
            String str = random.nextInt(2) % 2 == 0 ? "num" : "char";
            if ("char".equalsIgnoreCase(str)) {
                // 产生a-z或者A-Z字母
                int nextInt = random.nextInt(2) % 2 == 0 ? 65 : 97;
                val.append((char) (nextInt + random.nextInt(26)));
            } else {
                // 产生0-9数字
                val.append(random.nextInt(10));
            }
        }
        return val.toString();
    }

    /**
     * 生成指定长度随机数UUID,字母(字母包含大小写)
     *
     * @param len 指定长度
     * @return 随机数UUID字符串
     */
    public static String getUuidByCharacter(int len) {
        if (len <= 0) {
            throw new RuntimeException("长度要大于0");
        }
        StringBuilder val = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < len; i++) {
            // 产生a-z或者A-Z字母
            int nextInt = random.nextInt(2) % 2 == 0 ? 65 : 97;
            val.append((char) (nextInt + random.nextInt(26)));
        }
        return val.toString();
    }

    /**
     * 生成随机数UUID
     *
     * @return 随机数UUID字符串
     */
    public static String getUuid() {
        StringBuilder val = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 32; i++) {
            String str = random.nextInt(2) % 2 == 0 ? "num" : "char";
            if ("char".equalsIgnoreCase(str)) {
                // 产生a-z字母
                val.append((char) (97 + random.nextInt(26)));
            } else {
                // 产生0-9数字
                val.append(random.nextInt(10));
            }
            if (i == 7) {
                val.append("-");
            }
            if (i == 11 || i == 15 || i == 19) {
                val.append("-");
            }
        }
        return val.toString();
    }

    /**
     * 生成指定长度的随机整数
     *
     * @param len 长度
     * @return 随机整数
     */
    public static String getRandomInt(int len) {
        if (len <= 0) {
            throw new RuntimeException("长度要大于0");
        }
        StringBuilder rs = new StringBuilder();
        for (int i = 0; i < len; i++) {
            int a = getRandomInt0To9();
            //首位数字不能为0
            if (0 == i) {
                while (0 == a) {
                    a = getRandomInt0To9();
                }
            }
            rs.append(a);
        }
        return rs.toString();
    }

    /**
     * 获取一个0-9的整数
     *
     * @return 0-9的整数
     */
    public static Integer getRandomInt0To9() {
        return getRandomIntByBound(10);
    }

    /**
     * 获取一个0-指定范围的整数
     *
     * @param bound 范围
     * @return 0-指定范围的整数
     */
    public static Integer getRandomIntByBound(int bound) {
        Random r = new Random();
        return r.nextInt(bound);
    }
}


博客评论
还没有人评论,赶紧抢个沙发~
发表评论
说明:请文明发言,共建和谐网络,您的个人信息不会被公开显示。