Android 身份證號校驗

時間:2016年5月25日18:31:01

作者:JustDo23

說明:在錄入用戶信息的時候有時候會需要填寫居民身份證號信息,對于身份證號信息的校驗,看到同事在項目中塞入了這個判斷的工具類,本人在簡單瀏覽和修改之后第二次進行總結。

01. 居民身份證號

  • 首先,就目前而言基本所有人的身份證都升級到了二代身份證。
  • 其次,身份證的編碼是有規(guī)則的,這個真的需要百科一下,進行簡單理解。
  • 公民身份號碼是特征組合碼,由十七位數(shù)字本體碼和一位數(shù)字校驗碼組成。
  • 排列順序從左至右依次為:六位數(shù)字地址碼,八位數(shù)字出生日期碼,三位數(shù)字順序碼和一位數(shù)字校驗碼。
  • 身份證的尾號可以是X這個是大寫的X。最后一位是0-10的校驗位,大寫的X代表了10。其實是羅馬數(shù)字。
  • 更多信息在百度百科有介紹。

本次總結中,用戶輸入的最后一位不區(qū)分大小寫X,感覺不太對。哈哈。

02. EditText輸入身份證號

使用EditText來接收用戶的輸入,同時需要限制用戶輸入的字符,可以對EditText進設置輸入類型和監(jiān)聽來實現(xiàn)。示例代碼如下:

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

對EditText設置輸入的監(jiān)聽

// 在這里設置才有用![對EditText可以輸入的字符進行了限制][使用Android原生的鍵盤會停留在數(shù)字鍵盤無切換到英文鍵盤][第三方的鍵盤正常使用]
// 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. 校驗工具類

工具類的封裝主要也是根據(jù)身份證號的定義規(guī)則進行的。里邊包含了15位和18位的身份證號的校驗。主要的核心是根據(jù)前邊的數(shù)字計算出最后一位校驗位,計算結果和真實最后一位進行對比。工具類具體代碼如下:

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) : "";
    }

    /**
     * 得到身份證的區(qū)縣代碼。
     *
     * @return 區(qū)縣代碼。
     */
    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() {

        /*非閏年天數(shù)*/
        int[] monthDayN = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        /*閏年天數(shù)*/
        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符合規(guī)范, false不符合規(guī)范]
     */
    public static boolean isRealIDCard(String IdCard) {
        if (IdCard != null) {
            int correct = new IdCardUtil(IdCard).isCorrect();
            if (0 == correct) {// 符合規(guī)范
                return true;
            }
        }
        return false;
    }
}

04. 正則校驗

除了上邊的具體工具之外,同時可以使用正則表達式進行身份證的簡單校驗??梢栽谏线単工具類RegexUtil中添加真正表達式的代碼。

// 判斷是否符合身份證號碼的規(guī)范
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沒有進行修改,以上同時兼容輸入大小寫。
  • 代碼并沒有寫上完整的注釋,很多方法本人沒有用到。
  • 核心工具類代碼并非本人原創(chuàng)。如果找到網(wǎng)絡地址,會后期附上。
  • 文檔中復制了太多的代碼,似乎寫個demo更好一些。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,769評論 25 709
  • 為什么有的人身份證最后一位的號碼是0、1或2、3、4、5、6、7、8、9或X,而有的人是X這是怎么回事的呢,又有多...
    吳富良閱讀 8,887評論 0 1
  • 申明:本文除特別說明外,身份證號碼專指18位公民身份號碼 一、身份證號碼結構 早期‘身份證號碼’叫‘社會保障號’,...
    安東的漫長歲月閱讀 23,833評論 0 4
  • 笑來老師一直是在各種不同場合不停的重復傳遞價值的人,不害怕別人說啰嗦,堅持要做這個世界的好人。 其實大家都知道一個...
    Zhou_b739閱讀 174評論 0 1

友情鏈接更多精彩內容