记录,备查!  

  
1 /**
  2
  * 文件描述:检查身份证。
  3  */
  4 package com.baofeng.util;
  5 
  6 import java.util.ArrayList;
  7 import java.util.Calendar;
  8 import java.util.HashMap;
  9 import java.util.List;
 10 import java.util.Map;
 11 import java.util.regex.Matcher;
 12 import java.util.regex.Pattern;
 13 
 14 /**
 15  * @author liuyf8688
 16  *
 17  */
 18 public class IdCardUtil {
 19     
 20     /** 省、市身份证号前两位 **/
 21     private static final Map<Integer, String> PROVINCE_AND_CITY = new HashMap<Integer, String>();
 22     /** 判断规范 **/
 23     private static final Pattern CARD_NO_REG = Pattern.compile("(^\\d{15}$)|(^\\d{17}(\\d|x)$)");
 24     /** 身份证15位时,次序为省(3位)市(3位)年(2位)月(2位)日(2位)校验位(3位),皆为数字 **/
 25     private final static Pattern FIFTEEN_BIRTHDAY = Pattern.compile("(\\d{6})(\\d{2})(\\d{2})(\\d{2})(\\d{3})");
 26     /** 身份证18位时,次序为省(3位)市(3位)年(4位)月(2位)日(2位)校验位(4位),校验位末尾可能为x **/
 27     private final static Pattern EIGHTEEN_BIRTHDAY = Pattern.compile("(\\d{6})(\\d{4})(\\d{2})(\\d{2})(\\d{3})([0-9]|x)");
 28     /** 身份证本体位每位权值 */
 29     private static final int[] powers = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
 30     /** 校验位候选值 */
 31     private static final char[] parityBits = {'1', '0', 'x', '9', '8', '7', '6', '5', '4', '3', '2'};
 32     
 33     
 34     
 35     public static boolean isValid(String cardNo) {
 36         return isCardNo(cardNo) && checkProvince(cardNo) && checkBirthday(cardNo) && checkParity(cardNo);
 37     }
 38     
 39     /**
 40      * 功能描述:判断规范
 41      * @param cardNo
 42      * @return
 43      */
 44     private static boolean isCardNo(String cardNo) {        
 45         return CARD_NO_REG.matcher(cardNo).matches();        
 46     }
 47     
 48     /**
 49      * 功能描述:判断省份
 50      * @param cardNo
 51      * @return
 52      */
 53     private static boolean checkProvince(String cardNo) {
 54         if(PROVINCE_AND_CITY.get(Integer.valueOf(cardNo.substring(0, 2))) != null) {
 55             return true;
 56         }
 57         return false;
 58     }
 59         
 60     /**
 61      * 功能描述:判断生日是否正确
 62      * @param cardNo
 63      * @return
 64      */
 65     private static boolean checkBirthday(String cardNo) {
 66         
 67         String[] groups = splitToGroups(cardNo);
 68         //
 69         if(cardNo.length() == 15) {
 70             int year = 1900 + Integer.valueOf(groups[2]);
 71             int month = Integer.valueOf(groups[3]);
 72             int day = Integer.valueOf(groups[4]);
 73             Calendar calendar = Calendar.getInstance();
 74             calendar.set(year, month, day);
 75             return verifyBirthday(year, month, day, calendar);
 76         }
 77         //
 78         if(cardNo.length() == 18) {
 79             
 80             int year = Integer.valueOf(groups[2]);
 81             int month = Integer.valueOf(groups[3]);
 82             int day = Integer.valueOf(groups[4]);
 83             Calendar calendar = Calendar.getInstance();
 84             calendar.set(year, month - 1, day);
 85             return verifyBirthday(year, month, day, calendar);
 86         }
 87         
 88         return false;
 89     }
 90     
 91     /**
 92      * 功能:检验出生日期
 93      * @param year
 94      * @param month
 95      * @param day
 96      * @param calendar
 97      * @return
 98      */
 99     private static boolean verifyBirthday(int year, int month, int day, Calendar calendar) {
100         
101         if((calendar.get(Calendar.YEAR) == year)
102                 && ((calendar.get(Calendar.MONTH) + 1) == month)
103                 && (calendar.get(Calendar.DAY_OF_MONTH) == day)) {
104             int currYear = Calendar.getInstance().get(Calendar.YEAR);
105             int age = currYear - year;
106             if((age >= 3) && (age <=100)) {
107                 return true;
108             }
109         }
110         return false;
111     }
112     
113     /**
114      * 功能:判断身份证号码的校验位是否正确
115      * @param cardNo
116      * @return
117      */
118     private static boolean checkParity(String cardNo) {
119         //
120         if(cardNo.length() == 15) {
121             cardNo = convert15To18Bit(cardNo);
122         }
123         //
124         int digitalCode = 0;
125         if(cardNo.length() == 18) {
126             for(int i = 0; i < 17; i ++) {
127                 digitalCode += Integer.valueOf(cardNo.substring(i, i + 1)) * powers[i];
128             }
129             //
130             if(cardNo.substring(17, 18).equals(String.valueOf(parityBits[digitalCode % 11]))){
131                 return true;
132             }
133         }
134         return false;
135     }
136     
137     /**
138      * 功能:将15身份证号码转换成18位
139      * @param cardNo
140      * @return
141      */
142     private static String convert15To18Bit(String cardNo) {
143         
144         cardNo = cardNo.substring(0, 6) + "19" + cardNo.substring(6, cardNo.length());
145         //
146         int digitalCode = 0;
147         for(int i = 0; i < 17; i ++) {
148             digitalCode += Integer.valueOf(cardNo.substring(i, i + 1)) * powers[i];
149         }
150         //
151         cardNo += parityBits[digitalCode % 11];
152         return cardNo;
153     }
154     
155     /**
156      * 功能描述:将身份证号按照正则表达式分组。
157      * @param cardNo
158      * @return
159      */
160     private static String[] splitToGroups(String cardNo) {
161         
162         List<String> groups = new ArrayList<String>();
163         //
164         if(cardNo.length() == 15) {
165             Matcher matcher = FIFTEEN_BIRTHDAY.matcher(cardNo);
166             boolean matchFound = matcher.find();
167             if (matchFound) {
168                 for (int i=0; i<=matcher.groupCount(); i++) {
169                     groups.add(matcher.group(i));
170                 }
171             }
172         }
173         //
174         if(cardNo.length() == 18) {
175             Matcher matcher = EIGHTEEN_BIRTHDAY.matcher(cardNo);
176             boolean matchFound = matcher.find();
177             if (matchFound) {
178                 for (int i=0; i<=matcher.groupCount(); i++) {
179                     groups.add(matcher.group(i));
180                 }
181             }
182         }
183         
184         return groups.toArray(new String[0]);
185     }
186     
187     static{
188         //11:"北京",12:"天津",13:"河北",14:"山西",15:"内蒙古",21:"辽宁",22:"吉林",23:"黑龙江",31:"上海",32:"江苏",
189         PROVINCE_AND_CITY.put(11, "北京");
190         PROVINCE_AND_CITY.put(12, "天津");
191         PROVINCE_AND_CITY.put(13, "河北");
192         PROVINCE_AND_CITY.put(14, "山西");
193         PROVINCE_AND_CITY.put(15, "内蒙古");
194         PROVINCE_AND_CITY.put(21, "辽宁");
195         PROVINCE_AND_CITY.put(22, "吉林");
196         PROVINCE_AND_CITY.put(23, "黑龙江");
197         PROVINCE_AND_CITY.put(31, "上海");
198         PROVINCE_AND_CITY.put(32, "江苏");
199         //33:"浙江",34:"安徽",35:"福建",36:"江西",37:"山东",41:"河南",42:"湖北",43:"湖南",44:"广东",45:"广西",
200         PROVINCE_AND_CITY.put(33, "浙江");
201         PROVINCE_AND_CITY.put(34, "安徽");
202         PROVINCE_AND_CITY.put(35, "福建");
203         PROVINCE_AND_CITY.put(36, "江西");
204         PROVINCE_AND_CITY.put(37, "山东");
205         PROVINCE_AND_CITY.put(41, "河南");
206         PROVINCE_AND_CITY.put(42, "湖北");
207         PROVINCE_AND_CITY.put(43, "湖南");
208         PROVINCE_AND_CITY.put(44, "广东");        
209         PROVINCE_AND_CITY.put(45, "广西");
210         //46:"海南",50:"重庆",51:"四川",52:"贵州",53:"云南",54:"西藏",61:"陕西",62:"甘肃",63:"青海",64:"宁夏",
211         PROVINCE_AND_CITY.put(46, "海南");
212         PROVINCE_AND_CITY.put(50, "重庆");
213         PROVINCE_AND_CITY.put(51, "四川");
214         PROVINCE_AND_CITY.put(52, "贵州");
215         PROVINCE_AND_CITY.put(53, "云南");
216         PROVINCE_AND_CITY.put(54, "西藏");
217         PROVINCE_AND_CITY.put(61, "陕西");
218         PROVINCE_AND_CITY.put(62, "甘肃");
219         PROVINCE_AND_CITY.put(63, "青海");
220         PROVINCE_AND_CITY.put(64, "宁夏");
221         //65:"新疆",71:"台湾",81:"香港",82:"澳门",91:"国外"
222         PROVINCE_AND_CITY.put(65, "新疆");
223         PROVINCE_AND_CITY.put(71, "台湾");
224         PROVINCE_AND_CITY.put(81, "香港");
225         PROVINCE_AND_CITY.put(82, "澳门");
226         PROVINCE_AND_CITY.put(91, "国外");
227     }
228 }
229