java中身份证的验证以及身份证的各项的由来

身份证号码构成:6位地址编码,8位生日,3位顺序码和1位校验码

6位地址编码:表示编码对象常住户口所在县(市、旗、区)的行政区域划分代码,按GB/T2260的规定执行

8位生日:表示编码对象出生的年、月、日,按GB/T7408的规定执行,年、月、日代码之间不用分隔符和空格。

3位顺序码:表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,注意:顺序码的奇数分配给男性,偶数分配给女性

1位校验码:校验码是根据前面十七位数字码,按照ISO 7064:1983.MOD 11-2校验码计算出来的检验码。

校验位的计算:

通过S = Sum(Ai * Wi), i = 0, ... , 16 ,先对前17位数字的权求和

  S = Ai * Wi, i = 2, ... , 18
       Y = mod(S, 11)
       i: 表示号码字符从右至左包括校验码字符在内的位置序号
       Ai:表示第i位置上的身份证号码字符值
       Wi:表示第i位置上的加权因子
       i:      18    17    16     15    14    13    12    11    10    9     8     7     6     5    4    3    2    1

       Wi:    7      9     10      5      8      4      2      1      6     3     7     9    10    5    8    4    2    1

其中加权因子的由来

第一项 2^(18-1)%11=131072%11=7  第二项:2^(17-1)%11=65536%11=9 第三项 2^15%11=32768%11=10 第四项:2^14%11=16384%11=5......................第15项:2^(4-1)%11=8,第16项:2^(3-1)%11=4第17项:2^(2-1)%11=2 第18项:2(1-1)%11=1


最后一位值对应的校验码字符值:
             Y:     0    1    2    3    4    5    6    7    8    9    10
       校验码:   1    0    X    9    8    7    6    5    4    3     2

比如身份证号:14010519921101051* 求*所代表的值

Ai: 1  4   0   1  0  5  1  9  9  2  1  1  0   1  0  5  1   *

Wi:7  9  10  5  8  4  2  1  6  3  7  9  10  5  8  4  2  1

S = Ai * Wi=7+36+0+5+0+20+2+9+54+6+7+9+0+5+0+20+2=175

S=175/11=15+10/11
Y = mod(S, 11)=mod(217,11)=10

第十位所对应的校验码为2,所以*为2

身份证号为:140105199211010512


代码修改自http://blog.csdn.net/cecoo/article/details/4954522




import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Date:2015/9/7.
 */
public class IDCard {
    public static String IDCardValidate(String IDStr) {
        String errorInfo = "";// 记录错误信息
        String[] ValCodeArr = { "1", "0", "x", "9", "8", "7", "6", "5", "4","3", "2" };
        String[] Wi = { "7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7","9", "10", "5", "8", "4", "2" };
        String Ai = "";
 String cityCode[] = { "11", "12", "13", "14", "15", "21", "22",
                "23", "31", "32", "33", "34", "35", "36", "37", "41", "42", "43",
                "44", "45", "46", "50", "51", "52", "53", "54", "61", "62", "63",
                "64", "65", "71", "81", "82", "91" };//省份

        if (IDStr.length() != 15 && IDStr.length() != 18) {
            errorInfo = "身份证号码长度应该为15位或18位。";
            return errorInfo;
        }
        if (IDStr.length() == 18) {
            Ai = IDStr.substring(0, 17);
        }else if (IDStr.length() == 15){
            Ai = IDStr.substring(0, 6) + "19" + IDStr.substring(6, 15);
        }
        if (isNumeric(Ai) == false) {
            errorInfo = "身份证15位号码都应为数字 ; 18位号码除最后一位外,都应为数字。";
            return errorInfo;
        }

        String provinceid = IDStr.substring(0, 2);
        boolean flag = false;
        for (String id : cityCode) {
            if (id.equals(provinceid)) {
                flag = true;
                break;
            }
        }
        if (!flag) {
            errorInfo = "身份证省份无效。";
            return errorInfo;
        }

        String strYear = Ai.substring(6, 10);// 年份
        String strMonth = Ai.substring(10, 12);// 月份
        String strDay = Ai.substring(12, 14);// 日份
        if (isDate(strYear + "-" + strMonth + "-" + strDay) == false) {
            errorInfo = "身份证生日无效。";
            return errorInfo;
        }
        GregorianCalendar gc = new GregorianCalendar();
        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");
        try {
            if ((gc.get(Calendar.YEAR) - Integer.parseInt(strYear)) > 150
                    || (gc.getTime().getTime() - s.parse(
                    strYear + "-" + strMonth + "-" + strDay).getTime()) < 0) {
                errorInfo = "身份证生日不在有效范围。";
                return errorInfo;
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
        } catch (java.text.ParseException e) {
            e.printStackTrace();
        }
        if (Integer.parseInt(strMonth) > 12 || Integer.parseInt(strMonth) == 0) {
            errorInfo = "身份证月份无效";
            return errorInfo;
        }
        if (Integer.parseInt(strDay) > 31 || Integer.parseInt(strDay) == 0) {
            errorInfo = "身份证日期无效";
            return errorInfo;
        }

        int TotalmulAiWi = 0;
        for (int i = 0; i < 17; i++) {
            TotalmulAiWi = TotalmulAiWi
                    + Integer.parseInt(String.valueOf(Ai.charAt(i)))
                    * Integer.parseInt(Wi[i]);
        }
        int modValue = TotalmulAiWi % 11;
        String strVerifyCode = ValCodeArr[modValue];
        Ai = Ai + strVerifyCode;

        if (IDStr.length() == 18) {
            if (Ai.equals(IDStr) == false) {
                errorInfo = "身份证无效,不是合法的身份证号码";
                return errorInfo;
            }
        } else {
            return "";
        }
        return "";
    }

    /**
     * 功能:判断字符串是否为数字
     *
     * @param str
     * @return
     */
    private static boolean isNumeric(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(str);
        if (isNum.matches()) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * 功能:
     * @param strDate  YYYY-MM-DD
     * @return
     */
    public static boolean isDate(String strDate) {
        Pattern pattern = Pattern.compile("(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0

[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)");
        Matcher m = pattern.matcher(strDate);
        if (m.matches()) {
            return true;
        } else {
            return false;
        }
    }

    public static void main(String[] args) throws ParseException {

       String IDCardNums="430421197710177894";
        IDCard cc = new IDCard();

        System.out.println(cc.IDCardValidate(IDCardNum));

        System.out.println(cc.isDate("1996-01-31"));
    }
}

代码修改自http://blog.csdn.net/cecoo/article/details/4954522  代码主要修改了将年月日通过正则表达式中加入了闰年和平年的判定,将省份的判断减少了代码


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值