参考:
本文将使用Java实现中国公民(15位或者18位)身份证号码的相关验证,功能如下:
- 身份证号有效性验证
- 分析详细身份证信息
- 生成一个虚拟的省份证号码。
身份证号码验证
- 号码的结构 公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。
- 地址码(前六位数)
表示编码对象常住户口所在县(市、旗、区)的行政区划代码,按GB/T2260的规定执行。 - 出生日期码(第七位至十四位)
表示编码对象出生的年、月、日,按GB/T7408的规定执行,年、月、日代码之间不用分隔符。 - 顺序码(第十五位至十七位)
表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号, 顺序码的奇数分配给男性,偶数分配给女性。 - 校验码(第十八位数)
(1)十七位数字本体码加权求和公式 S = Sum(Ai * Wi), i = 0, … , 16 ,先对前17位数字的权求和
Ai:表示第i位置上的身份证号码数字值
Wi:表示第i位置上的加权因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
(2)计算模 Y = mod(S, 11)
(3)通过模得到对应的校验码 Y: 0 1 2 3 4 5 6 7 8 9 10 校验码: 1 0 X 9 8 7 6 5 4 3 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
package com.jdk5.blog.IDValidator; import java.util.HashMap; import java.util.Map; public class IDValidator { private Map<String, String> gb2260 = GB2260.getInstance(); private static Map<String, IDCodeInfo> cache = new HashMap<String, IDCodeInfo>(); /** * 身份证是否有效 * * @param id * {@link String} * @return {@link Boolean} */ public boolean isValid(String id) { IDCodeInfo code = Utils.checkArg(id); if (code == null) { return false; } // 查询cache if (cache.containsKey(id)) { return cache.get(id).isValid(); } Utils.parseCode(code); if (!(Utils.checkAddr(code.getAddrCode()) && Utils.checkBirth(code.getBirthCode()) && Utils .checkOrder(code.getOrder()))) { code.setValid(false); cache.put(id, code); return false; } // 15位不含校验码,到此已结束 if (code.getType() == 15) { code.setValid(true); cache.put(id, code); return true; } /* 校验位部分 */ // 位置加权 int[] posWeight = new int[17]; for (int i = 18; i > 1; i--) { int wei = Utils.weight(i); posWeight[18 - i] = wei; } // 累加body部分与位置加权的积 int bodySum = 0; String[] bodyArr = code.getBody().split(""); for (int j = 0; j < bodyArr.length; j++) { bodySum += (Integer.valueOf(bodyArr[j], 10) * posWeight[j]); } // 得出校验码 int tempCheckBit = 12 - (bodySum % 11); String checkBit = String.valueOf(tempCheckBit); if (tempCheckBit == 10) { checkBit = "X"; } else if (tempCheckBit > 10) { checkBit = String.valueOf(tempCheckBit % 11); } // 检查校验码 if (!checkBit.equals(code.getCheckBit())) { code.setValid(false); cache.put(id, code); return false; } else { code.setValid(true); cache.put(id, code); return true; } } /** * 分析详细信息 * * @param id * {@link String} 身份证号 * @return {@link IDCodeInfo} */ public IDCodeInfo getInfo(String id) { // 号码必须有效 if (this.isValid(id) == false) { return null; } // TODO 复用此部分 IDCodeInfo code = Utils.checkArg(id); // 查询cache // 到此时通过isValid已经有了cache记录 if (cache.containsKey(id)) { return cache.get(id); } Utils.parseCode(code); // 记录cache cache.put(id, code); return code; } /** * 仿造一个号 * * @param isFifteen * 是否生成15位数 * @return */ public String makeID(boolean isFifteen) { // 地址码 String addr = ""; if (gb2260 != null) { int loopCnt = 0; while (addr == "") { // 防止死循环 if (loopCnt > 10) { addr = "110101"; break; } String prov = Utils.strPad(String.valueOf(Utils.rand(50, 1)), 2, '0', false); String city = Utils.strPad(String.valueOf(Utils.rand(60, 1)), 2, '0', false); String area = Utils.strPad(String.valueOf(Utils.rand(20, 1)), 2, '0', false); String addrTest = prov + city + area; if (gb2260.containsKey(addrTest)) { addr = addrTest; break; } } } else { addr = "110101"; } // 出生年 String yr = Utils.strPad(String.valueOf(Utils.rand(99, 50)), 2, '0', false); String mo = Utils.strPad(String.valueOf(Utils.rand(12, 1)), 2, '0', false); String da = Utils.strPad(String.valueOf(Utils.rand(28, 1)), 2, '0', false); if (isFifteen) { return addr + yr + mo + da + Utils.strPad(String.valueOf(Utils.rand(999, 1)), 3, '1', false); } yr = "19" + yr; String body = addr + yr + mo + da + Utils.strPad(String.valueOf(Utils.rand(999, 1)), 3, '1', false); // 位置加权 int[] posWeight = new int[17]; for (int i = 18; i > 1; i--) { int wei = Utils.weight(i); posWeight[18 - i] = wei; } // 累加body部分与位置加权的积 int bodySum = 0; String[] bodyArr = body.split(""); for (int j = 0; j < bodyArr.length; j++) { bodySum += (Integer.valueOf(bodyArr[j], 10) * posWeight[j]); } // 得出校验码 int tempCheckBit = 12 - (bodySum % 11); String checkBit = String.valueOf(tempCheckBit); if (tempCheckBit == 10) { checkBit = "X"; } else if (tempCheckBit > 10) { checkBit = String.valueOf(tempCheckBit % 11); } return (body + checkBit); } } |
调用方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//初始化一个实例 IDValidator validator = new IDValidator(); //验证身份证是否有效 validator.isValid("152103198909218022") //分析详细信息 validator.getInfo(id15) //生成18位身份证号 validator.makeID(false) //生成15位身份证号 validator.makeID(true) |
下载地址:下载地址
演示:Demo
没测试
src/test/java/目录的
com.jdk5.blog.IDValidator.IDValidatorTest.java
有个简单的测试