Java 身份证校验工具类(15位校验、18位校验与15转18)


身份证简介

身份证校验是指通过一定规则和算法对身份证号码进行真实性核验的过程,主要是为了确保个人身份信息的准确性和安全性。

(一)身份证号码的组成

我国公民身份证号码一般为18位,由以下四部分组成:

  • 地址码:前6位数字,表示编码对象常住户口所在县(市、旗、区)的行政区划代码。
  • 出生日期码:接下来的8位数字,表示编码对象出生的年、月、日,其中年份用四位数字表示,年、月、日之间不用分隔符。
  • 顺序码:第15至17位数字,表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人员编定的顺序号。顺序码的奇数分给男性,偶数分给女性。
  • 校验码:最后一位数字,是根据前面十七位数字码,按照ISO 7064:1983标准的MOD 11-2校验算法计算得出的检验码。

(二)一代和二代身份证

一代身份证

  1. 发布时间与停用时间

    • 发布时间:1984年。
    • 停用时间:2013年1月1日。
  2. 外观与规格

    • 采用聚酯薄膜密封、单页卡式设计。
    • 尺寸为特定规格(但具体尺寸未明确提及,与二代证不同)。
    • 15位编码。
  3. 制作技术与防伪措施

    • 最初采用印刷和照相翻拍技术塑封而成。
    • 防伪性能相对较差,比较容易被伪造。
    • 1995年7月1日起启用新的防伪居民身份证,采用全息透视塑封套防伪技术。
  4. 信息内容

    • 包括姓名、性别、民族、出生日期、常住户口所在地住址等基本信息。
    • 最初发放的身份证中有一部分是用手工填写的。
    • 不包含“婚姻状况”和“职业”等内容。
  5. 有效性与使用范围

    • 在有效期内继续有效,但自2013年起停止使用。
    • 用于常住户口登记项目变更、兵役登记、婚姻登记、收养登记、申请办理出境手续等场合。

二代身份证

  1. 发布时间与换发时间

    • 发布并实施时间:依据2003年6月28日通过的《中华人民共和国居民身份证法》。
    • 换发时间:自2004年1月1日起开始换发。
  2. 外观与规格

    • 采用多层聚酯材料复合而成的单页卡式设计。
    • 尺寸为85.6mm×54.0mm×1.0mm,四角为圆角。
    • 正面印有国徽、证件名称、长城图案、签发机关和有效期以及彩虹扭索花纹;背面印有姓名、性别、民族、出生日期、常住户口所在地住址、公民身份号码和本人相片。
  3. 制作技术与防伪措施

    • 采用非接触式IC卡技术制作,具备视读和机读两种功能。
    • 芯片存储量大,信息可划分安全等级并分区存储。
    • 表面采用防伪膜和多项印刷防伪技术,如彩虹印刷、荧光印刷、定向光变色膜等。
  4. 信息内容

    • 包含姓名、性别、民族、出生日期、常住户口所在地住址、公民身份号码等基本信息。
    • 公民身份号码为18位,其中前6位为地区码,中间8位为出生年月日,后3位为顺序码,最后1位为校验码。
  5. 有效性与使用范围

    • 按年龄区域划分使用期限:未满16周岁为5年,16至25周岁为10年,26至45周岁为20年,46周岁以上为长期有效。
    • 用于各类需要身份验证的场合,如银行、机场、酒店等。
    • 在公安、社保、医疗等领域自动采集和录入相关数据,提高工作效率和准确性。

检验思路分析

15位和18位身份证的检验思路分析,主要涉及到身份证号码的组成规则以及校验方法的了解。以下是对两者的详细检验思路:

(一)15位身份证号码

  1. 格式检查

    • 确认身份证号码长度为15位。
    • 检查每一位是否都是数字。
  2. 组成规则分析

    • 前6位:地区编码,表示身份证持有人的户籍所在地。
    • 第7-8位:出生年份的后两位。
    • 第9-10位:出生月份。
    • 第11-12位:出生日期。
    • 第13-14位:顺序码,为随机数,用于区分同年同月同日出生的不同个体。
    • 第15位:性别码,奇数为男性,偶数为女性。
  3. 校验内容

    • 年份:检查年份是否在合理范围内(如1900-1999年的后两位)。
    • 月份:检查月份是否在01-12之间。
    • 日期:检查日期是否在01-31之间,注意不同月份的天数差异。
    • 性别:根据第15位判断性别是否符合奇数为男、偶数为女的规则。

(二)18位身份证号码

  1. 格式检查

    • 确认身份证号码长度为18位。
    • 检查前17位是否都是数字,最后一位可以是数字或字母X(代表10)。
  2. 组成规则分析

    • 前6位:地区编码,表示身份证持有人的户籍所在地。
    • 第7-14位:出生年月日,完整的8位数字,格式为YYYYMMDD。
    • 第15-17位:顺序码,其中第17位还用于表示性别,奇数为男性,偶数为女性。
    • 第18位:校验码,根据前17位数字通过特定算法计算得出。
  3. 校验内容

    • 地区码:需与全国行政区划代码一致,可通过查询最新的行政区划代码表进行验证。
    • 出生日期:需符合日期格式(YYYYMMDD),且年份应在合理范围内(如当前年份的前几十年至建国初期)。
    • 顺序码:第17位需根据性别规则进行校验(奇数表示男性,偶数表示女性)。
    • 校验码:按照特定算法计算前17位的加权和,取模后得到余数,再根据余数在校验码对照表中查找对应的校验码。如果计算出的校验码与身份证号码中的第18位一致,则校验通过;否则,校验不通过。

(三)校验算法示例(18位)

  1. 将前17位数字分别乘以对应的加权因子(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2)。
  2. 将乘积相加得到总和。
  3. 将总和除以11得到余数。
  4. 根据余数在校验码对照表(1, 0, X, 9, 8, 7, 6, 5, 4, 3, 2)中查找对应的校验码。

编写代码

(一)创建工具类IdentityUtils

public class IdentityUtils {                                                                                                      
    // 权重因子                                                                                                                       
    private static final int[] COEFFICIENT_ARRAY = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};                         
    // 校验码字符集                                                                                                                     
    private static final String[] IDENTITY_MANTISSA = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};                    
    // 15位身份证正则表达式                                                                                                                
    private static final String IDENTITY_PATTERN_15 = "^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0-2]\\d)|3[0-1])\\d{3}$";                  
    // 18位身份证正则表达式                                                                                                                
    private static final String IDENTITY_PATTERN_18 = "^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0-2]\\d)|3[0-1])\\d{3}[0-9Xx]$";
} 

(二)创建isLegalIdCard方法

基础校验:判断身份证位数是否位15位或18位、是否为空。

public static boolean isLegalIdCard(String identity) {
    if (identity == null) {                           
        return false;                                 
    }                                                 
    if (identity.length() == 15) {                    
        return is15BitLegalIdCard(identity);          
    }                                                 
    if (identity.length() == 18) {                    
        return is18BitLegalIdCard(identity);          
    }                                                 
    return false;                                     
}                                                     

(三)创建is15BitLegalIdCard方法

简易校验:15位身份证号码是否合法(年份、月份、日期和性别)。

public static boolean is15BitLegalIdCard(String identity) {                            
    // 正则表达式用于初步格式检查                                                                   
    if (!identity.matches(IDENTITY_PATTERN_15)) {                                      
        return false;                                                                  
    }                                                                                  
                                                                                       
    // 提取年份(后两位)、月份、日期和顺序码(含性别码)                                                       
    String yearStr = identity.substring(6, 8);                                         
    String monthStr = identity.substring(8, 10);                                       
    String dayStr = identity.substring(10, 12);                                        
    String sequenceStr = identity.substring(12, 15);                                   
                                                                                       
    // 检查年份是否在合理范围内(1900-1999年的后两位)                                                    
    int year = Integer.parseInt(yearStr);                                              
    if (year < 0 || year > 99) {                                                       
        return false;                                                                  
    }                                                                                  
                                                                                       
    // 检查月份和日期是否在合理范围内                                                                 
    int month = Integer.parseInt(monthStr);                                            
    int day = Integer.parseInt(dayStr);                                                
    if (month < 1 || month > 12 || day < 1 || day > 31) {                              
        return false;                                                                  
    }                                                                                  
                                                                                       
    // 检查性别码(第15位,奇数为男性,偶数为女性)                                                         
    int genderCode = Integer.parseInt(sequenceStr.substring(sequenceStr.length() - 1));
    if (genderCode < 0 || genderCode > 9 ) {                                           
        return false;                                                                  
    }                                                                                  
    return true;                                                                       
}                                                                                      

(四)创建is18BitLegalIdCard方法

简易校验:18位身份证号码是否合法(校验码)。

public static boolean is18BitLegalIdCard(String identity) { 
    // 正则表达式用于初步格式检查                                        
    if (!identity.matches(IDENTITY_PATTERN_18)) {           
        return false;                                       
    }                                                       
    // 将字符串对象中的字符转换为一个字符数组                                  
    char[] chars = identity.toCharArray();                  
    long sum = IntStream.range(0, 17).map(index -> {        
        char ch = chars[index];                             
        // 通俗理解:digit()是个边界值判断,不过边界返回字符数字本身数值,超过边界即返回 -1.   
        int digit = Character.digit(ch, 10);                
        int coefficient = COEFFICIENT_ARRAY[index];         
        return digit * coefficient;                         
    }).summaryStatistics().getSum();                        
                                                            
    // 计算出的尾数索引                                             
    int mantissaIndex = (int) (sum % 11);                   
    String mantissa = IDENTITY_MANTISSA[mantissaIndex];     
                                                            
    String lastChar = identity.substring(17);               
    return lastChar.equalsIgnoreCase(mantissa);             
}                                                           

(五)创建convert15To18BitIdCard方法

简易转换:15位身份证号码转18位身份证号码。

public static String convert15To18BitIdCard(String identity) {                                     
    if (!is15BitLegalIdCard(identity)) {                                                           
        throw new IllegalArgumentException("Invalid 15-bit ID card number");                       
    }                                                                                              
                                                                                                   
    // 提取各个部分                                                                                      
    String regionCode = identity.substring(0, 6);                                                  
    String year = identity.substring(6, 8);                                                        
    String month = identity.substring(8, 10);                                                      
    String day = identity.substring(10, 12);                                                       
    String orderCode = identity.substring(12);                                                     
                                                                                                   
    // 将年份扩展为四位                                                                                    
    int yearInt = Integer.parseInt(year);                                                          
    String extendedYear = (yearInt > 30 ? "19" : "20") + year;                                     
                                                                                                   
    // 组合成17位(不含校验码)                                                                               
    String idWithoutCheckCode = regionCode + extendedYear + month + day + orderCode;               
                                                                                                   
    // 计算校验码                                                                                       
    int checkSum = 0;                                                                              
    for (int i = 0; i < 17; i++) {                                                                 
        checkSum += Character.getNumericValue(idWithoutCheckCode.charAt(i)) * COEFFICIENT_ARRAY[i];
    }                                                                                              
    int mod = checkSum % 11;                                                                       
    String checkCode = IDENTITY_MANTISSA[mod];                                                     
                                                                                                   
    // 组合成18位                                                                                      
    return idWithoutCheckCode + checkCode;                                                         
}                                                                                                  

(六)创建测试类

package net.army.com.experiment.experiment03;

import java.util.Scanner;

/**
 * 功能:身份证校验测试
 * 日期:2024年11月16日
 * 作者:梁辰兴
 */
public class IDNumber {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.print("请输入身份证号码:");
            String number = sc.next();
            if (IdentityUtils.isLegalIdCard(number)) {
                if (IdentityUtils.is15BitLegalIdCard(number)) {
                    System.out.println("身份证号码:"+number + " 为标准15位身份证!");
                    String newNumber = IdentityUtils.convert15To18BitIdCard(number);
                    System.out.println("转换为18位标准身份证号码:"+newNumber);
                    break;
                } else if (IdentityUtils.is18BitLegalIdCard(number)) {
                    System.out.println("身份证号码:"+number + " 为标准18位身份证!");
                    break;
                }
            } else {
                System.out.println(number + "不是合法身份证,请重新输出!");
            }
        }
    }
}

运行测试

15位身份证号码示例:

110105491231001
320322480630452
510104470101003
652923460229124
440524450715678

18位身份证号码示例:

11010519491231001X
320322194806304528
510104194701010032
652923194602291247
440524194507156789
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梁辰兴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值