实现从15位~18位的身份证号码转换,校验中国大陆公民身份证、香港居民身份证、澳门身份证和台湾身份证。
[代码] [Java]代码
002 |
* Copyright (C) 2009-2010 Yichuan, Fuchun All rights reserved. |
003 |
* Licensed to the Apache Software Foundation (ASF) under one or more |
004 |
* contributor license agreements. See the NOTICE file distributed with |
005 |
* this work for additional information regarding copyright ownership. |
006 |
* The ASF licenses this file to You under the Apache License, Version 2.0 |
007 |
* (the "License"); you may not use this file except in compliance with |
008 |
* the License. You may obtain a copy of the License at |
009 |
* http://www./licenses/LICENSE-2.0 |
010 |
* Unless required by applicable law or agreed to in writing, software |
011 |
* distributed under the License is distributed on an "AS IS" BASIS, |
012 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
013 |
* See the License for the specific language governing permissions and |
014 |
* limitations under the License. |
015 |
* @(#) IdcardUtils.java Date: 2010-06-17 |
019 |
import java.text.ParseException; |
020 |
import java.text.SimpleDateFormat; |
021 |
import java.util.Calendar; |
022 |
import java.util.Date; |
023 |
import java.util.HashMap; |
024 |
import java.util.Map; |
026 |
import org.apache.commons.lang.StringUtils; |
032 |
* @version 1.0, 2010-06-17 |
034 |
public class IdcardUtils extends StringUtils { |
036 |
/** 中国公民身份证号码最小长度。 */ |
037 |
public static final int CHINA_ID_MIN_LENGTH = 15 ; |
039 |
/** 中国公民身份证号码最大长度。 */ |
040 |
public static final int CHINA_ID_MAX_LENGTH = 18 ; |
043 |
public static final String cityCode[] = { |
044 |
"11" , "12" , "13" , "14" , "15" , "21" , "22" , "23" , "31" , "32" , "33" , "34" , "35" , "36" , "37" , "41" , |
045 |
"42" , "43" , "44" , "45" , "46" , "50" , "51" , "52" , "53" , "54" , "61" , "62" , "63" , "64" , "65" , "71" , |
050 |
public static final int power[] = { |
051 |
7 , 9 , 10 , 5 , 8 , 4 , 2 , 1 , 6 , 3 , 7 , 9 , 10 , 5 , 8 , 4 , 2 |
055 |
public static final String verifyCode[] = { |
056 |
"1" , "0" , "X" , "9" , "8" , "7" , "6" , "5" , "4" , "3" , "2" |
059 |
public static final int MIN = 1930 ; |
060 |
public static Map<String, String> cityCodes = new HashMap<String, String>(); |
062 |
public static Map<String, Integer> twFirstCode = new HashMap<String, Integer>(); |
064 |
public static Map<String, Integer> hkFirstCode = new HashMap<String, Integer>(); |
066 |
cityCodes.put( "11" , "北京" ); |
067 |
cityCodes.put( "12" , "天津" ); |
068 |
cityCodes.put( "13" , "河北" ); |
069 |
cityCodes.put( "14" , "山西" ); |
070 |
cityCodes.put( "15" , "内蒙古" ); |
071 |
cityCodes.put( "21" , "辽宁" ); |
072 |
cityCodes.put( "22" , "吉林" ); |
073 |
cityCodes.put( "23" , "黑龙江" ); |
074 |
cityCodes.put( "31" , "上海" ); |
075 |
cityCodes.put( "32" , "江苏" ); |
076 |
cityCodes.put( "33" , "浙江" ); |
077 |
cityCodes.put( "34" , "安徽" ); |
078 |
cityCodes.put( "35" , "福建" ); |
079 |
cityCodes.put( "36" , "江西" ); |
080 |
cityCodes.put( "37" , "山东" ); |
081 |
cityCodes.put( "41" , "河南" ); |
082 |
cityCodes.put( "42" , "湖北" ); |
083 |
cityCodes.put( "43" , "湖南" ); |
084 |
cityCodes.put( "44" , "广东" ); |
085 |
cityCodes.put( "45" , "广西" ); |
086 |
cityCodes.put( "46" , "海南" ); |
087 |
cityCodes.put( "50" , "重庆" ); |
088 |
cityCodes.put( "51" , "四川" ); |
089 |
cityCodes.put( "52" , "贵州" ); |
090 |
cityCodes.put( "53" , "云南" ); |
091 |
cityCodes.put( "54" , "西藏" ); |
092 |
cityCodes.put( "61" , "陕西" ); |
093 |
cityCodes.put( "62" , "甘肃" ); |
094 |
cityCodes.put( "63" , "青海" ); |
095 |
cityCodes.put( "64" , "宁夏" ); |
096 |
cityCodes.put( "65" , "新疆" ); |
097 |
cityCodes.put( "71" , "台湾" ); |
098 |
cityCodes.put( "81" , "香港" ); |
099 |
cityCodes.put( "82" , "澳门" ); |
100 |
cityCodes.put( "91" , "国外" ); |
101 |
twFirstCode.put( "A" , 10 ); |
102 |
twFirstCode.put( "B" , 11 ); |
103 |
twFirstCode.put( "C" , 12 ); |
104 |
twFirstCode.put( "D" , 13 ); |
105 |
twFirstCode.put( "E" , 14 ); |
106 |
twFirstCode.put( "F" , 15 ); |
107 |
twFirstCode.put( "G" , 16 ); |
108 |
twFirstCode.put( "H" , 17 ); |
109 |
twFirstCode.put( "J" , 18 ); |
110 |
twFirstCode.put( "K" , 19 ); |
111 |
twFirstCode.put( "L" , 20 ); |
112 |
twFirstCode.put( "M" , 21 ); |
113 |
twFirstCode.put( "N" , 22 ); |
114 |
twFirstCode.put( "P" , 23 ); |
115 |
twFirstCode.put( "Q" , 24 ); |
116 |
twFirstCode.put( "R" , 25 ); |
117 |
twFirstCode.put( "S" , 26 ); |
118 |
twFirstCode.put( "T" , 27 ); |
119 |
twFirstCode.put( "U" , 28 ); |
120 |
twFirstCode.put( "V" , 29 ); |
121 |
twFirstCode.put( "X" , 30 ); |
122 |
twFirstCode.put( "Y" , 31 ); |
123 |
twFirstCode.put( "W" , 32 ); |
124 |
twFirstCode.put( "Z" , 33 ); |
125 |
twFirstCode.put( "I" , 34 ); |
126 |
twFirstCode.put( "O" , 35 ); |
127 |
hkFirstCode.put( "A" , 1 ); |
128 |
hkFirstCode.put( "B" , 2 ); |
129 |
hkFirstCode.put( "C" , 3 ); |
130 |
hkFirstCode.put( "R" , 18 ); |
131 |
hkFirstCode.put( "U" , 21 ); |
132 |
hkFirstCode.put( "Z" , 26 ); |
133 |
hkFirstCode.put( "X" , 24 ); |
134 |
hkFirstCode.put( "W" , 23 ); |
135 |
hkFirstCode.put( "O" , 15 ); |
136 |
hkFirstCode.put( "N" , 14 ); |
146 |
public static String conver15CardTo18(String idCard) { |
147 |
String idCard18 = "" ; |
148 |
if (idCard.length() != CHINA_ID_MIN_LENGTH) { |
153 |
String birthday = idCard.substring( 6 , 12 ); |
154 |
Date birthDate = null ; |
156 |
birthDate = new SimpleDateFormat( "yyMMdd" ).parse(birthday); |
157 |
} catch (ParseException e) { |
160 |
Calendar cal = Calendar.getInstance(); |
161 |
if (birthDate != null ) |
162 |
cal.setTime(birthDate); |
164 |
String sYear = String.valueOf(cal.get(Calendar.YEAR)); |
165 |
idCard18 = idCard.substring( 0 , 6 ) + sYear + idCard.substring( 8 ); |
167 |
char [] cArr = idCard18.toCharArray(); |
169 |
int [] iCard = converCharToInt(cArr); |
170 |
int iSum17 = getPowerSum(iCard); |
172 |
String sVal = getCheckCode18(iSum17); |
173 |
if (sVal.length() > 0 ) { |
188 |
public static boolean validateCard(String idCard) { |
189 |
String card = idCard.trim(); |
190 |
if (validateIdCard18(card)) { |
193 |
if (validateIdCard15(card)) { |
196 |
String[] cardval = validateIdCard10(card); |
197 |
if (cardval != null ) { |
198 |
if (cardval[ 2 ].equals( "true" )) { |
211 |
public static boolean validateIdCard18(String idCard) { |
212 |
boolean bTrue = false ; |
213 |
if (idCard.length() == CHINA_ID_MAX_LENGTH) { |
215 |
String code17 = idCard.substring( 0 , 17 ); |
217 |
String code18 = idCard.substring( 17 , CHINA_ID_MAX_LENGTH); |
219 |
char [] cArr = code17.toCharArray(); |
221 |
int [] iCard = converCharToInt(cArr); |
222 |
int iSum17 = getPowerSum(iCard); |
224 |
String val = getCheckCode18(iSum17); |
225 |
if (val.length() > 0 ) { |
226 |
if (val.equalsIgnoreCase(code18)) { |
243 |
public static boolean validateIdCard15(String idCard) { |
244 |
if (idCard.length() != CHINA_ID_MIN_LENGTH) { |
248 |
String proCode = idCard.substring( 0 , 2 ); |
249 |
if (cityCodes.get(proCode) == null ) { |
252 |
String birthCode = idCard.substring( 6 , 12 ); |
253 |
Date birthDate = null ; |
255 |
birthDate = new SimpleDateFormat( "yy" ).parse(birthCode.substring( 0 , 2 )); |
256 |
} catch (ParseException e) { |
259 |
Calendar cal = Calendar.getInstance(); |
260 |
if (birthDate != null ) |
261 |
cal.setTime(birthDate); |
262 |
if (!valiDate(cal.get(Calendar.YEAR), Integer.valueOf(birthCode.substring( 2 , 4 )), |
263 |
Integer.valueOf(birthCode.substring( 4 , 6 )))) { |
278 |
* [0] - 台湾、澳门、香港 [1] - 性别(男M,女F,未知N) [2] - 是否合法(合法true,不合法false) |
282 |
public static String[] validateIdCard10(String idCard) { |
283 |
String[] info = new String[ 3 ]; |
284 |
String card = idCard.replaceAll( "[\\(|\\)]" , "" ); |
285 |
if (card.length() != 8 && card.length() != 9 && idCard.length() != 10 ) { |
288 |
if (idCard.matches( "^[a-zA-Z][0-9]{9}$" )) { |
290 |
System.out.println( "11111" ); |
291 |
String char2 = idCard.substring( 1 , 2 ); |
292 |
if (char2.equals( "1" )) { |
294 |
System.out.println( "MMMMMMM" ); |
295 |
} else if (char2.equals( "2" )) { |
297 |
System.out.println( "FFFFFFF" ); |
301 |
System.out.println( "NNNN" ); |
304 |
info[ 2 ] = validateTWCard(idCard) ? "true" : "false" ; |
305 |
} else if (idCard.matches( "^[1|5|7][0-9]{6}\\(?[0-9A-Z]\\)?$" )) { |
309 |
} else if (idCard.matches( "^[A-Z]{1,2}[0-9]{6}\\(?[0-9A]\\)?$" )) { |
312 |
info[ 2 ] = validateHKCard(idCard) ? "true" : "false" ; |
326 |
public static boolean validateTWCard(String idCard) { |
327 |
String start = idCard.substring( 0 , 1 ); |
328 |
String mid = idCard.substring( 1 , 9 ); |
329 |
String end = idCard.substring( 9 , 10 ); |
330 |
Integer iStart = twFirstCode.get(start); |
331 |
Integer sum = iStart / 10 + (iStart % 10 ) * 9 ; |
332 |
char [] chars = mid.toCharArray(); |
334 |
for ( char c : chars) { |
335 |
sum = sum + Integer.valueOf(c + "" ) * iflag; |
338 |
return (sum % 10 == 0 ? 0 : ( 10 - sum % 10 )) == Integer.valueOf(end) ? true : false ; |
342 |
* 验证香港身份证号码(存在Bug,部份特殊身份证无法检查) |
344 |
* 身份证前2位为英文字符,如果只出现一个英文字符则表示第一位是空格,对应数字58 前2位英文字符A-Z分别对应数字10-35 |
345 |
* 最后一位校验码为0-9的数字加上字符"A","A"代表10 |
348 |
* 将身份证号码全部转换为数字,分别对应乘9-1相加的总和,整除11则证件号码有效 |
351 |
* @param idCard 身份证号码 |
354 |
public static boolean validateHKCard(String idCard) { |
355 |
String card = idCard.replaceAll( "[\\(|\\)]" , "" ); |
357 |
if (card.length() == 9 ) { |
358 |
sum = (Integer.valueOf(card.substring( 0 , 1 ).toUpperCase().toCharArray()[ 0 ]) - 55 ) * 9 |
359 |
+ (Integer.valueOf(card.substring( 1 , 2 ).toUpperCase().toCharArray()[ 0 ]) - 55 ) * 8 ; |
360 |
card = card.substring( 1 , 9 ); |
362 |
sum = 522 + (Integer.valueOf(card.substring( 0 , 1 ).toUpperCase().toCharArray()[ 0 ]) - 55 ) * 8 ; |
364 |
String mid = card.substring( 1 , 7 ); |
365 |
String end = card.substring( 7 , 8 ); |
366 |
char [] chars = mid.toCharArray(); |
368 |
for ( char c : chars) { |
369 |
sum = sum + Integer.valueOf(c + "" ) * iflag; |
372 |
if (end.toUpperCase().equals( "A" )) { |
375 |
sum = sum + Integer.valueOf(end); |
377 |
return (sum % 11 == 0 ) ? true : false ; |
387 |
public static int [] converCharToInt( char [] ca) { |
389 |
int [] iArr = new int [len]; |
391 |
for ( int i = 0 ; i < len; i++) { |
392 |
iArr[i] = Integer.parseInt(String.valueOf(ca[i])); |
394 |
} catch (NumberFormatException e) { |
401 |
* 将身份证的每位和对应位的加权因子相乘之后,再得到和值 |
406 |
public static int getPowerSum( int [] iArr) { |
408 |
if (power.length == iArr.length) { |
409 |
for ( int i = 0 ; i < iArr.length; i++) { |
410 |
for ( int j = 0 ; j < power.length; j++) { |
412 |
iSum = iSum + iArr[i] * power[j]; |
421 |
* 将power和值与11取模获得余数进行校验码判断 |
426 |
public static String getCheckCode18( int iSum) { |
473 |
public static int getAgeByIdCard(String idCard) { |
475 |
if (idCard.length() == CHINA_ID_MIN_LENGTH) { |
476 |
idCard = conver15CardTo18(idCard); |
478 |
String year = idCard.substring( 6 , 10 ); |
479 |
Calendar cal = Calendar.getInstance(); |
480 |
int iCurrYear = cal.get(Calendar.YEAR); |
481 |
iAge = iCurrYear - Integer.valueOf(year); |
489 |
* @return 生日(yyyyMMdd) |
491 |
public static String getBirthByIdCard(String idCard) { |
492 |
Integer len = idCard.length(); |
493 |
if (len < CHINA_ID_MIN_LENGTH) { |
495 |
} else if (len == CHINA_ID_MIN_LENGTH) { |
496 |
idCard = conver15CardTo18(idCard); |
498 |
return idCard.substring( 6 , 14 ); |
507 |
public static Short getYearByIdCard(String idCard) { |
508 |
Integer len = idCard.length(); |
509 |
if (len < CHINA_ID_MIN_LENGTH) { |
511 |
} else if (len == CHINA_ID_MIN_LENGTH) { |
512 |
idCard = conver15CardTo18(idCard); |
514 |
return Short.valueOf(idCard.substring( 6 , 10 )); |
524 |
public static Short getMonthByIdCard(String idCard) { |
525 |
Integer len = idCard.length(); |
526 |
if (len < CHINA_ID_MIN_LENGTH) { |
528 |
} else if (len == CHINA_ID_MIN_LENGTH) { |
529 |
idCard = conver15CardTo18(idCard); |
531 |
return Short.valueOf(idCard.substring( 10 , 12 )); |
541 |
public static Short getDateByIdCard(String idCard) { |
542 |
Integer len = idCard.length(); |
543 |
if (len < CHINA_ID_MIN_LENGTH) { |
545 |
} else if (len == CHINA_ID_MIN_LENGTH) { |
546 |
idCard = conver15CardTo18(idCard); |
548 |
return Short.valueOf(idCard.substring( 12 , 14 )); |
555 |
* @return 性别(M-男,F-女,N-未知) |
557 |
public static String getGenderByIdCard(String idCard) { |
558 |
String sGender = "N" ; |
559 |
if (idCard.length() == CHINA_ID_MIN_LENGTH) { |
560 |
idCard = conver15CardTo18(idCard); |
562 |
String sCardNum = idCard.substring( 16 , 17 ); |
563 |
if (Integer.parseInt(sCardNum) % 2 != 0 ) { |
577 |
public static String getProvinceByIdCard(String idCard) { |
578 |
int len = idCard.length(); |
579 |
String sProvince = null ; |
580 |
String sProvinNum = "" ; |
581 |
if (len == CHINA_ID_MIN_LENGTH || len == CHINA_ID_MAX_LENGTH) { |
582 |
sProvinNum = idCard.substring( 0 , 2 ); |
584 |
sProvince = cityCodes.get(sProvinNum); |
594 |
public static boolean isNum(String val) { |
595 |
return val == null || "" .equals(val) ? false : val.matches( "^[0-9]*$" ); |
609 |
public static boolean valiDate( int iYear, int iMonth, int iDate) { |
610 |
Calendar cal = Calendar.getInstance(); |
611 |
int year = cal.get(Calendar.YEAR); |
613 |
if (iYear < MIN || iYear >= year) { |
616 |
if (iMonth < 1 || iMonth > 12 ) { |
627 |
boolean dm = ((iYear % 4 == 0 && iYear % 100 != 0 ) || (iYear % 400 == 0 )) |
628 |
&& (iYear > MIN && iYear < year); |
629 |
datePerMonth = dm ? 29 : 28 ; |
634 |
return (iDate >= 1 ) && (iDate <= datePerMonth); |
|