身份证验证

  1 package com.app.cq.utils;
  2 
  3 import java.text.ParseException;
  4 import java.text.SimpleDateFormat;
  5 import java.util.Calendar;
  6 import java.util.Date;
  7 /**
  8  * Created by CWQ on 2018-01-04.
  9  */
 10 /**
 11  * <p>
 12  * 身份证合法性校验
 13  * </p>
 14  *
 15  * <pre>
 16  * --15位身份证号码:第7、8位为出生年份(两位数),第9、10位为出生月份,第11、12位代表出生日期,第15位代表性别,奇数为男,偶数为女。
 17  * --18位身份证号码:第7、8、9、10位为出生年份(四位数),第11、第12位为出生月份,第13、14位代表出生日期,第17位代表性别,奇数为男,偶数为女。
 18  *    最后一位为校验位
 19  * </pre>
 20  *
 21  * @author 313921
 22  */
 23 public class IdcardValidator {
 24 
 25         /**
 26          * <pre>
 27          * 省、直辖市代码表:
 28          *     11 : 北京  12 : 天津  13 : 河北       14 : 山西  15 : 内蒙古
 29          *     21 : 辽宁  22 : 吉林  23 : 黑龙江  31 : 上海  32 : 江苏
 30          *     33 : 浙江  34 : 安徽  35 : 福建       36 : 江西  37 : 山东
 31          *     41 : 河南  42 : 湖北  43 : 湖南       44 : 广东  45 : 广西      46 : 海南
 32          *     50 : 重庆  51 : 四川  52 : 贵州       53 : 云南  54 : 西藏
 33          *     61 : 陕西  62 : 甘肃  63 : 青海       64 : 宁夏  65 : 新疆
 34          *     71 : 台湾
 35          *     81 : 香港  82 : 澳门
 36          *     91 : 国外
 37          * </pre>
 38          */
 39         private static String cityCode[] = { "11", "12", "13", "14", "15", "21",
 40                 "22", "23", "31", "32", "33", "34", "35", "36", "37", "41", "42",
 41                 "43", "44", "45", "46", "50", "51", "52", "53", "54", "61", "62",
 42                 "63", "64", "65", "71", "81", "82", "91" };
 43 
 44         /**
 45          * 每位加权因子
 46          */
 47         private static int power[] = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5,
 48                 8, 4, 2 };
 49 
 50         /**
 51          * 验证所有的身份证的合法性
 52          *
 53          * @param idcard
 54          *            身份证
 55          * @return 合法返回true,否则返回false
 56          */
 57         public static boolean isValidatedAllIdcard(String idcard) {
 58             if (idcard == null || "".equals(idcard)) {
 59                 return false;
 60             }
 61             if (idcard.length() == 15) {
 62                 return validate15IDCard(idcard);
 63             }
 64             return validate18Idcard(idcard);
 65         }
 66 
 67         /**
 68          * <p>
 69          * 判断18位身份证的合法性
 70          * </p>
 71          * 根据〖中华人民共和国国家标准GB11643-1999〗中有关公民身份号码的规定,公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。
 72          * 排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。
 73          * <p>
 74          * 顺序码: 表示在同一地址码所标识的区域范围内,对同年、同月、同 日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配 给女性。
 75          * </p>
 76          * <p>
 77          * 1.前1、2位数字表示:所在省份的代码; 2.第3、4位数字表示:所在城市的代码; 3.第5、6位数字表示:所在区县的代码;
 78          * 4.第7~14位数字表示:出生年、月、日; 5.第15、16位数字表示:所在地的派出所的代码;
 79          * 6.第17位数字表示性别:奇数表示男性,偶数表示女性;
 80          * 7.第18位数字是校检码:也有的说是个人信息码,一般是随计算机的随机产生,用来检验身份证的正确性。校检码可以是0~9的数字,有时也用x表示。
 81          * </p>
 82          * <p>
 83          * 第十八位数字(校验码)的计算方法为: 1.将前面的身份证号码17位数分别乘以不同的系数。从第一位到第十七位的系数分别为:7 9 10 5 8 4
 84          * 2 1 6 3 7 9 10 5 8 4 2
 85          * </p>
 86          * <p>
 87          * 2.将这17位数字和系数相乘的结果相加。
 88          * </p>
 89          * <p>
 90          * 3.用加出来和除以11,看余数是多少
 91          * </p>
 92          * 4.余数只可能有0 1 2 3 4 5 6 7 8 9 10这11个数字。其分别对应的最后一位身份证的号码为1 0 X 9 8 7 6 5 4 3
 93          * 2。
 94          * <p>
 95          * 5.通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10,身份证的最后一位号码就是2。
 96          * </p>
 97          *
 98          * @param idcard
 99          * @return
100          */
101         public static boolean validate18Idcard(String idcard) {
102             if (idcard == null) {
103                 return false;
104             }
105 
106             // 非18位为假
107             if (idcard.length() != 18) {
108                 return false;
109             }
110             // 获取前17位
111             String idcard17 = idcard.substring(0, 17);
112 
113             // 前17位全部为数字
114             if (!isDigital(idcard17)) {
115                 return false;
116             }
117 
118             String provinceid = idcard.substring(0, 2);
119             // 校验省份
120             if (!checkProvinceid(provinceid)) {
121                 return false;
122             }
123 
124             // 校验出生日期
125             String birthday = idcard.substring(6, 14);
126 
127             SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
128 
129             try {
130                 Date birthDate = sdf.parse(birthday);
131                 String tmpDate = sdf.format(birthDate);
132                 if (!tmpDate.equals(birthday)) {// 出生年月日不正确
133                     return false;
134                 }
135 
136             } catch (ParseException e1) {
137 
138                 return false;
139             }
140 
141             // 获取第18位
142             String idcard18Code = idcard.substring(17, 18);
143 
144             char c[] = idcard17.toCharArray();
145 
146             int bit[] = converCharToInt(c);
147 
148             int sum17 = 0;
149 
150             sum17 = getPowerSum(bit);
151 
152             // 将和值与11取模得到余数进行校验码判断
153             String checkCode = getCheckCodeBySum(sum17);
154             if (null == checkCode) {
155                 return false;
156             }
157             // 将身份证的第18位与算出来的校码进行匹配,不相等就为假
158             if (!idcard18Code.equalsIgnoreCase(checkCode)) {
159                 return false;
160             }
161 
162             return true;
163         }
164 
165         /**
166          * 校验15位身份证
167          *
168          * <pre>
169          * 只校验省份和出生年月日
170          * </pre>
171          *
172          * @param idcard
173          * @return
174          */
175         public static boolean validate15IDCard(String idcard) {
176             if (idcard == null) {
177                 return false;
178             }
179             // 非15位为假
180             if (idcard.length() != 15) {
181                 return false;
182             }
183 
184             // 15全部为数字
185             if (!isDigital(idcard)) {
186                 return false;
187             }
188 
189             String provinceid = idcard.substring(0, 2);
190             // 校验省份
191             if (!checkProvinceid(provinceid)) {
192                 return false;
193             }
194 
195             String birthday = idcard.substring(6, 12);
196 
197             SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
198 
199             try {
200                 Date birthDate = sdf.parse(birthday);
201                 String tmpDate = sdf.format(birthDate);
202                 if (!tmpDate.equals(birthday)) {// 身份证日期错误
203                     return false;
204                 }
205 
206             } catch (ParseException e1) {
207 
208                 return false;
209             }
210 
211             return true;
212         }
213 
214         /**
215          * 将15位的身份证转成18位身份证
216          *
217          * @param idcard
218          * @return
219          */
220         public static String convertIdcarBy15bit(String idcard) {
221             if (idcard == null) {
222                 return null;
223             }
224 
225             // 非15位身份证
226             if (idcard.length() != 15) {
227                 return null;
228             }
229 
230             // 15全部为数字
231             if (!isDigital(idcard)) {
232                 return null;
233             }
234 
235             String provinceid = idcard.substring(0, 2);
236             // 校验省份
237             if (!checkProvinceid(provinceid)) {
238                 return null;
239             }
240 
241             String birthday = idcard.substring(6, 12);
242 
243             SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
244 
245             Date birthdate = null;
246             try {
247                 birthdate = sdf.parse(birthday);
248                 String tmpDate = sdf.format(birthdate);
249                 if (!tmpDate.equals(birthday)) {// 身份证日期错误
250                     return null;
251                 }
252 
253             } catch (ParseException e1) {
254                 return null;
255             }
256 
257             Calendar cday = Calendar.getInstance();
258             cday.setTime(birthdate);
259             String year = String.valueOf(cday.get(Calendar.YEAR));
260 
261             String idcard17 = idcard.substring(0, 6) + year + idcard.substring(8);
262 
263             char c[] = idcard17.toCharArray();
264             String checkCode = "";
265 
266             // 将字符数组转为整型数组
267             int bit[] = converCharToInt(c);
268 
269             int sum17 = 0;
270             sum17 = getPowerSum(bit);
271 
272             // 获取和值与11取模得到余数进行校验码
273             checkCode = getCheckCodeBySum(sum17);
274 
275             // 获取不到校验位
276             if (null == checkCode) {
277                 return null;
278             }
279             // 将前17位与第18位校验码拼接
280             idcard17 += checkCode;
281             return idcard17;
282         }
283 
284         /**
285          * 校验省份
286          *
287          * @param provinceid
288          * @return 合法返回TRUE,否则返回FALSE
289          */
290         private static boolean checkProvinceid(String provinceid) {
291             for (String id : cityCode) {
292                 if (id.equals(provinceid)) {
293                     return true;
294                 }
295             }
296             return false;
297         }
298 
299         /**
300          * 数字验证
301          *
302          * @param str
303          * @return
304          */
305         private static boolean isDigital(String str) {
306             return str.matches("^[0-9]*$");
307         }
308 
309         /**
310          * 将身份证的每位和对应位的加权因子相乘之后,再得到和值
311          *
312          * @param bit
313          * @return
314          */
315         private static int getPowerSum(int[] bit) {
316 
317             int sum = 0;
318 
319             if (power.length != bit.length) {
320                 return sum;
321             }
322 
323             for (int i = 0; i < bit.length; i++) {
324                 for (int j = 0; j < power.length; j++) {
325                     if (i == j) {
326                         sum = sum + bit[i] * power[j];
327                     }
328                 }
329             }
330             return sum;
331         }
332 
333         /**
334          * 将和值与11取模得到余数进行校验码判断
335          *
336          * @param checkCode
337          * @param sum17
338          * @return 校验位
339          */
340         private static String getCheckCodeBySum(int sum17) {
341             String checkCode = null;
342             switch (sum17 % 11) {
343                 case 10:
344                     checkCode = "2";
345                     break;
346                 case 9:
347                     checkCode = "3";
348                     break;
349                 case 8:
350                     checkCode = "4";
351                     break;
352                 case 7:
353                     checkCode = "5";
354                     break;
355                 case 6:
356                     checkCode = "6";
357                     break;
358                 case 5:
359                     checkCode = "7";
360                     break;
361                 case 4:
362                     checkCode = "8";
363                     break;
364                 case 3:
365                     checkCode = "9";
366                     break;
367                 case 2:
368                     checkCode = "x";
369                     break;
370                 case 1:
371                     checkCode = "0";
372                     break;
373                 case 0:
374                     checkCode = "1";
375                     break;
376             }
377             return checkCode;
378         }
379 
380         /**
381          * 将字符数组转为整型数组
382          *
383          * @param c
384          * @return
385          * @throws NumberFormatException
386          */
387         private static int[] converCharToInt(char[] c) throws NumberFormatException {
388             int[] a = new int[c.length];
389             int k = 0;
390             for (char temp : c) {
391                 a[k++] = Integer.parseInt(String.valueOf(temp));
392             }
393             return a;
394         }
395 
396         public static void main(String[] args) throws Exception {
397             String idcard15 = "130321860311519";
398             String idcard18 = "210102198617083732";//
399             // 15位身份证
400             System.out.println(isValidatedAllIdcard(idcard15));
401             // 18位身份证
402             System.out.println(isValidatedAllIdcard(idcard18));
403             // 15位身份证转18位身份证
404             System.out.println(convertIdcarBy15bit(idcard15));
405         }
406     }
View Code

 

posted on 2018-01-19 11:19  开心的小尾巴  阅读(135)  评论(0编辑  收藏  举报

导航