Android 身份证号校验

作者: JustDo23 | 来源:发表于2016-06-25 09:48 被阅读3513次

    时间:2016年5月25日18:31:01

    作者:JustDo23

    说明:在录入用户信息的时候有时候会需要填写居民身份证号信息,对于身份证号信息的校验,看到同事在项目中塞入了这个判断的工具类,本人在简单浏览和修改之后第二次进行总结。

    01. 居民身份证号

    • 首先,就目前而言基本所有人的身份证都升级到了二代身份证。
    • 其次,身份证的编码是有规则的,这个真的需要百科一下,进行简单理解。
    • 公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。
    • 排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。
    • 身份证的尾号可以是X这个是大写的X。最后一位是0-10的校验位,大写的X代表了10。其实是罗马数字。
    • 更多信息在百度百科有介绍。

    本次总结中,用户输入的最后一位不区分大小写X,感觉不太对。哈哈。

    02. EditText输入身份证号

    使用EditText来接收用户的输入,同时需要限制用户输入的字符,可以对EditText进设置输入类型和监听来实现。示例代码如下:

    // 居民身份证号的组成元素
    String[] IDCARD = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "x", "X", };
    

    对EditText设置输入的监听

    // 在这里设置才有用![对EditText可以输入的字符进行了限制][使用Android原生的键盘会停留在数字键盘无切换到英文键盘][第三方的键盘正常使用]
    // et_idcard.setInputType(InputType.TYPE_CLASS_TEXT);
    // et_idcard.setKeyListener(DigitsKeyListener.getInstance("1234567890Xx"));
    final List<String> idCardList = Arrays.asList(ConstantValues.IDCARD);
    InputFilter inputFilter = new InputFilter() {
    
        @Override
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
            // 返回空字符串,就代表匹配不成功,返回null代表匹配成功
            for (int i = 0; i < source.toString().length(); i++) {
                if (!idCardList.contains(String.valueOf(source.charAt(i)))) {
                    return "";
                }
                if (et_idcard.getText().toString().length() < 17) {
                    if ("x".equals(String.valueOf(source.charAt(i))) || "X".equals(String.valueOf(source.charAt(i)))) {
                        return "";
                    }
                }
            }
            return null;
        }
    };
    et_idcard.setFilters(new InputFilter[]{new InputFilter.LengthFilter(18), inputFilter});// 长度的限制和字符的限制
    

    03. 校验工具类

    工具类的封装主要也是根据身份证号的定义规则进行的。里边包含了15位和18位的身份证号的校验。主要的核心是根据前边的数字计算出最后一位校验位,计算结果和真实最后一位进行对比。工具类具体代码如下:

    import android.text.TextUtils;
    
    /**
     * 身份证的工具类
     */
    public class IdCardUtil {
    
        private String idCardNum = null;
    
        private static int IS_EMPTY = 1;
        private static int LEN_ERROR = 2;
        private static int CHAR_ERROR = 3;
        private static int DATE_ERROR = 4;
        private static int CHECK_BIT_ERROR = 5;
    
        private String[] errMsg = new String[]{"身份证完全正确!",
                "身份证为空!",
                "身份证长度不正确!",
                "身份证有非法字符!",
                "身份证中出生日期不合法!",
                "身份证校验位错误!"};
    
        private int error = 0;
    
        /**
         * 构造方法。
         *
         * @param idCardNum
         */
        public IdCardUtil(String idCardNum) {
            // super();
            this.idCardNum = idCardNum.trim();
            if (!TextUtils.isEmpty(this.idCardNum)) {
                this.idCardNum = this.idCardNum.replace("x", "X");
            }
        }
    
        public String getIdCardNum() {
            return idCardNum;
        }
    
        public void setIdCardNum(String idCardNum) {
            this.idCardNum = idCardNum;
            if (!TextUtils.isEmpty(this.idCardNum)) {
                this.idCardNum = this.idCardNum.replace("x", "X");
            }
        }
    
        /**
         * 得到身份证详细错误信息。
         *
         * @return 错误信息。
         */
        public String getErrMsg() {
            return this.errMsg[this.error];
        }
    
        /**
         * 是否为空。
         *
         * @return true: null  false: not null;
         */
        public boolean isEmpty() {
            if (this.idCardNum == null)
                return true;
            else
                return this.idCardNum.trim().length() > 0 ? false : true;
        }
    
        /**
         * 身份证长度。
         *
         * @return
         */
        public int getLength() {
            return this.isEmpty() ? 0 : this.idCardNum.length();
        }
    
        /**
         * 身份证长度。
         *
         * @return
         */
        public int getLength(String str) {
            return this.isEmpty() ? 0 : str.length();
        }
    
        /**
         * 是否是15位身份证。
         *
         * @return true: 15位  false:其他。
         */
        public boolean is15() {
            return this.getLength() == 15;
        }
    
        /**
         * 是否是18位身份证。
         *
         * @return true: 18位  false:其他。
         */
        public boolean is18() {
            return this.getLength() == 18;
        }
    
        /**
         * 得到身份证的省份代码。
         *
         * @return 省份代码。
         */
        public String getProvince() {
            return this.isCorrect() == 0 ? this.idCardNum.substring(0, 2) : "";
        }
    
        /**
         * 得到身份证的城市代码。
         *
         * @return 城市代码。
         */
        public String getCity() {
            return this.isCorrect() == 0 ? this.idCardNum.substring(2, 4) : "";
        }
    
        /**
         * 得到身份证的区县代码。
         *
         * @return 区县代码。
         */
        public String getCountry() {
            return this.isCorrect() == 0 ? this.idCardNum.substring(4, 6) : "";
        }
    
        /**
         * 得到身份证的出生年份。
         *
         * @return 出生年份。
         */
        public String getYear() {
            if (this.isCorrect() != 0)
                return "";
    
            if (this.getLength() == 15) {
                return "19" + this.idCardNum.substring(6, 8);
            } else {
                return this.idCardNum.substring(6, 10);
            }
        }
    
        /**
         * 得到身份证的出生月份。
         *
         * @return 出生月份。
         */
        public String getMonth() {
            if (this.isCorrect() != 0)
                return "";
    
            if (this.getLength() == 15) {
                return this.idCardNum.substring(8, 10);
            } else {
                return this.idCardNum.substring(10, 12);
            }
        }
    
        /**
         * 得到身份证的出生日子。
         *
         * @return 出生日期。
         */
        public String getDay() {
            if (this.isCorrect() != 0)
                return "";
    
            if (this.getLength() == 15) {
                return this.idCardNum.substring(10, 12);
            } else {
                return this.idCardNum.substring(12, 14);
            }
        }
    
        /**
         * 得到身份证的出生日期。
         *
         * @return 出生日期。
         */
        public String getBirthday() {
            if (this.isCorrect() != 0)
                return "";
    
            if (this.getLength() == 15) {
                return "19" + this.idCardNum.substring(6, 12);
            } else {
                return this.idCardNum.substring(6, 14);
            }
        }
    
        /**
         * 得到身份证的出生年月。
         *
         * @return 出生年月。
         */
        public String getBirthMonth() {
            return getBirthday().substring(0, 6);
        }
    
        /**
         * 得到身份证的顺序号。
         *
         * @return 顺序号。
         */
        public String getOrder() {
            if (this.isCorrect() != 0)
                return "";
    
            if (this.getLength() == 15) {
                return this.idCardNum.substring(12, 15);
            } else {
                return this.idCardNum.substring(14, 17);
            }
        }
    
        /**
         * 得到性别。
         *
         * @return 性别:1-男  2-女
         */
        public String getSex() {
            if (this.isCorrect() != 0)
                return "";
    
            int p = Integer.parseInt(getOrder());
            if (p % 2 == 1) {
                return "男";
            } else {
                return "女";
            }
        }
    
        /**
         * 得到性别值。
         *
         * @return 性别:1-男  2-女
         */
        public String getSexValue() {
            if (this.isCorrect() != 0)
                return "";
    
            int p = Integer.parseInt(getOrder());
            if (p % 2 == 1) {
                return "1";
            } else {
                return "2";
            }
        }
    
        /**
         * 得到校验位。
         *
         * @return 校验位。
         */
        public String getCheck() {
            if (!this.isLenCorrect())
                return "";
    
            String lastStr = this.idCardNum.substring(this.idCardNum.length() - 1);
            if ("x".equals(lastStr)) {
                lastStr = "X";
            }
            return lastStr;
        }
    
        /**
         * 得到15位身份证。
         *
         * @return 15位身份证。
         */
        public String to15() {
            if (this.isCorrect() != 0)
                return "";
    
            if (this.is15())
                return this.idCardNum;
            else
                return this.idCardNum.substring(0, 6) + this.idCardNum.substring(8, 17);
        }
    
        /**
         * 得到18位身份证。
         *
         * @return 18位身份证。
         */
        public String to18() {
            if (this.isCorrect() != 0)
                return "";
    
            if (this.is18())
                return this.idCardNum;
            else
                return this.idCardNum.substring(0, 6) + "19" + this.idCardNum.substring(6) + this.getCheckBit();
        }
    
        /**
         * 得到18位身份证。
         *
         * @return 18位身份证。
         */
        public static String toNewIdCard(String tempStr) {
            if (tempStr.length() == 18)
                return tempStr.substring(0, 6) + tempStr.substring(8, 17);
            else
                return tempStr.substring(0, 6) + "19" + tempStr.substring(6) + getCheckBit(tempStr);
        }
    
        /**
         * 校验身份证是否正确
         *
         * @return 0:正确
         */
        public int isCorrect() {
            if (this.isEmpty()) {
                this.error = IdCardUtil.IS_EMPTY;
                return this.error;
            }
    
            if (!this.isLenCorrect()) {
                this.error = IdCardUtil.LEN_ERROR;
                return this.error;
            }
    
            if (!this.isCharCorrect()) {
                this.error = IdCardUtil.CHAR_ERROR;
                return this.error;
            }
    
            if (!this.isDateCorrect()) {
                this.error = IdCardUtil.DATE_ERROR;
                return this.error;
            }
    
            if (this.is18()) {
                if (!this.getCheck().equals(this.getCheckBit())) {
                    this.error = IdCardUtil.CHECK_BIT_ERROR;
                    return this.error;
                }
            }
    
            return 0;
        }
    
    
        private boolean isLenCorrect() {
            return this.is15() || this.is18();
        }
    
        /**
         * 判断身份证中出生日期是否正确。
         *
         * @return
         */
        private boolean isDateCorrect() {
    
            /*非闰年天数*/
            int[] monthDayN = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
            /*闰年天数*/
            int[] monthDayL = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    
            int month;
            if (this.is15()) {
                month = Integer.parseInt(this.idCardNum.substring(8, 10));
            } else {
                month = Integer.parseInt(this.idCardNum.substring(10, 12));
            }
    
            int day;
            if (this.is15()) {
                day = Integer.parseInt(this.idCardNum.substring(10, 12));
            } else {
                day = Integer.parseInt(this.idCardNum.substring(12, 14));
            }
    
            if (month > 12 || month <= 0) {
                return false;
            }
    
            if (this.isLeapyear()) {
                if (day > monthDayL[month - 1] || day <= 0)
                    return false;
            } else {
                if (day > monthDayN[month - 1] || day <= 0)
                    return false;
            }
    
            return true;
        }
    
        /**
         * 得到校验位。
         *
         * @return
         */
        private String getCheckBit() {
            if (!this.isLenCorrect())
                return "";
    
            String temp = null;
            if (this.is18())
                temp = this.idCardNum;
            else
                temp = this.idCardNum.substring(0, 6) + "19" + this.idCardNum.substring(6);
    
    
            String checkTable[] = new String[]{"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
            int[] wi = new int[]{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1};
            int sum = 0;
    
            for (int i = 0; i < 17; i++) {
                String ch = temp.substring(i, i + 1);
                sum = sum + Integer.parseInt(ch) * wi[i];
            }
    
            int y = sum % 11;
    
            return checkTable[y];
        }
    
    
        /**
         * 得到校验位。
         *
         * @return
         */
        private static String getCheckBit(String str) {
    
            String temp = null;
            if (str.length() == 18)
                temp = str;
            else
                temp = str.substring(0, 6) + "19" + str.substring(6);
    
    
            String checkTable[] = new String[]{"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
            int[] wi = new int[]{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1};
            int sum = 0;
    
            for (int i = 0; i < 17; i++) {
                String ch = temp.substring(i, i + 1);
                sum = sum + Integer.parseInt(ch) * wi[i];
            }
    
            int y = sum % 11;
    
            return checkTable[y];
        }
    
    
        /**
         * 身份证号码中是否存在非法字符。
         *
         * @return true: 正确  false:存在非法字符。
         */
        private boolean isCharCorrect() {
            boolean iRet = true;
    
            if (this.isLenCorrect()) {
                byte[] temp = this.idCardNum.getBytes();
    
                if (this.is15()) {
                    for (int i = 0; i < temp.length; i++) {
                        if (temp[i] < 48 || temp[i] > 57) {
                            iRet = false;
                            break;
                        }
                    }
                }
    
                if (this.is18()) {
                    for (int i = 0; i < temp.length; i++) {
                        if (temp[i] < 48 || temp[i] > 57) {
                            if (i == 17 && temp[i] != 88) {
                                iRet = false;
                                break;
                            }
                        }
                    }
                }
            } else {
                iRet = false;
            }
            return iRet;
        }
    
        /**
         * 判断身份证的出生年份是否未闰年。
         *
         * @return true :闰年  false 平年
         */
        private boolean isLeapyear() {
            String temp;
    
            if (this.is15()) {
                temp = "19" + this.idCardNum.substring(6, 8);
            } else {
                temp = this.idCardNum.substring(6, 10);
            }
    
            int year = Integer.parseInt(temp);
    
            if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
                return true;
            else
                return false;
        }
    }
    

    04. 使用方法

    将使用方法封装在一个名为RegexUtil的工具类中。

    /**
     * 校验工具类
     *
     * @author JustDo23
     */
    public class RegexUtil {    
    
        /**
         * 比较真实完整的判断身份证号码的工具
         *
         * @param IdCard 用户输入的身份证号码
         * @return [true符合规范, false不符合规范]
         */
        public static boolean isRealIDCard(String IdCard) {
            if (IdCard != null) {
                int correct = new IdCardUtil(IdCard).isCorrect();
                if (0 == correct) {// 符合规范
                    return true;
                }
            }
            return false;
        }
    }
    

    04. 正则校验

    除了上边的具体工具之外,同时可以使用正则表达式进行身份证的简单校验。可以在上边g工具类RegexUtil中添加真正表达式的代码。

    // 判断是否符合身份证号码的规范
    public static boolean isIDCard(String IDCard) {
        if (IDCard != null) {
            String IDCardRegex = "(^\\d{15}$)|(^\\d{18}$)|(^\\d{17}(\\d|X|x|Y|y)$)";
            return IDCard.matches(IDCardRegex);
        }
        return false;
    }
    

    后记

    • 对于代码中大小写X没有进行修改,以上同时兼容输入大小写。
    • 代码并没有写上完整的注释,很多方法本人没有用到。
    • 核心工具类代码并非本人原创。如果找到网络地址,会后期附上。
    • 文档中复制了太多的代码,似乎写个demo更好一些。

    相关文章

      网友评论

        本文标题:Android 身份证号校验

        本文链接:https://www.haomeiwen.com/subject/hwmndttx.html