Java:身份證號的校驗與生成

Java:身份證號碼嚴格校驗,與生成

身份證前6位地區碼

緣由:現在好多手機端應用,藉助互聯網實名認證或安全等口號,向用戶索取更多的信息,比如綁定身份證。
根據網上關於身份證的百科,我寫了一個我認爲最嚴格的校驗身份證號碼,以及隨機生成身份證號的java代碼
(網上有很多身份證號檢驗,隨機生成身份證號 的網站)

校驗身份證代碼

package identity.card;

import java.io.FileReader;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Scanner;
import java.util.Set;
/*
 * 身份證組成:2(省級)2(地級市)2(縣級)8(出生:年月日)3(派出所代碼)1(校驗碼)
 * 其中第17位:奇數=男,偶數=女
    加權碼wi:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
    // 獲取校驗碼:將身份證 (前17位*加權碼)所得總和 再對11取餘=校驗碼索引
    校驗碼(18): 1 0 X 9 8 7 6 5 4 3 2 

 */

public class IdentityCard {
    private static Scanner sc;

    public static void main(String[] args) {
        try {
            idCard();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void idCard() throws Exception {
        sc = new Scanner(System.in);
        System.out.println("請輸入需要校驗的身份證號:");
        String id = sc.next();// id:身份證號
        // 正則初步:校驗身份證
        // 日期: ((0[1-9])|(1[0-2])):匹配"01-12"月
        // (([0-2][1-9])|10|20|30|31):匹配"01-31"天
        String regID = "[1-9]\\d{5}[1-9]\\d{3}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9xX]";
        if (!id.matches(regID)) {
            System.out.println("正則不匹配");
            return;
        }

        // 進一步:年月日校驗
        int year = Integer.parseInt(id.substring(6, 10));
        int month = Integer.parseInt(id.substring(10, 12));
        int day = Integer.parseInt(id.substring(12, 14));
        System.out.println(year + "," + month + "," + day);
        if (day > 28 && !isDate(year, month, day)) {
            System.out.println("日期規則不對");
            return;
        }

        // 再進一步:檢驗最後一位校驗碼
        // 獲取加權碼wi:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
        int[] wi = new int[17];
        for (int i = 1; i < 18; i++) {
            // 獲取加權數字
            int winum = (int) (Math.pow(2, i) % 11);
            // 將加權數反向存入數組
            wi[wi.length - i] = winum;
        }

        // 獲取加權後的總和
        int sum = 0;
        id = id.trim();// 去空格
        for (int i = 0; i < wi.length; i++) {
            // 獲取身份證前17位的每一位,轉換爲數字
            int j = Integer.parseInt(id.substring(i, i + 1));
            // 獲取加權後所得的和
            sum += (j * wi[i]);
        }

        // 匹配校驗碼
        String Ai = "10x987654342";
        // 獲取驗證碼索引:
        int index = sum % 11;
        // 比較輸入身份證與所得校驗碼比較(忽略大小寫)
        if (id.substring(17).equalsIgnoreCase(Ai.substring(index, index + 1))) {
            // 判斷男女
            System.out.println(((Integer.parseInt(id.substring(16, 17)) % 2) == 0) ? "女生" : "男生");
        } else {
            System.out.println("校驗不成功");
            return;
        }

        // isAreacode(id);//按行讀取地區編碼文檔,匹配法

        // 最後一步地區碼校驗.properties集合方法
        Properties p = new Properties();
        // 加載地區碼配置文件
        p.load(new FileReader("ID=Zone.txt"));
        Set<Entry<Object, Object>> entrySet = p.entrySet();
        boolean flag2 = true;

        for (Entry<Object, Object> entry : entrySet) {
            String key = (String) entry.getKey();
            // 匹配身份證所屬區域
            if (id.substring(0, 6).equals(key)) {
                System.out.println(entry.getValue());
                flag2 = false;
                break;
            }
        }
        if (flag2)
            System.out.println("沒有此地區:你的身份證有誤");
        else
            System.out.println("讀取結束");
    }

    // 進一步日期判斷
    public static boolean isDate(int year, int month, int day) {// day=29|30|31
        // 日期口訣: 一三五七八十臘(12月),三十一天永不差;平年二月二十八;閏年二月把一加 ;四六九冬(11月)三十日
        // 閏年:四年一閏,百年不閏,四百年再閏.
        if (month == 2) {// 當月份=2時
            if (day == 29 && (year % 4 == 0 && year % 100 != 0 | year % 400 == 0))
                return true;
            // 是2月非閏年
            return false;
        }
        // 天數是31天,月份卻是:4|6|9|11
        if (day == 31 && (month == 4 || month == 6 || month == 9 || month == 11))
            return false;
        // 其它正常情況
        return true;
    }
}

身份證隨機生成方法

public static void diyIdCard() {
        // 獲取6爲地區碼
        Random ra = new Random();
        // 以生成的隨機數=循環的次數:來獲取隨機地區碼
        int num = ra.nextInt(3465) + 1;
        int count = 0;// 循環次數
        String str1 = "";// 六位地區碼
        String zone = "";
        Properties p = new Properties();
        // 加載地區碼配置文件
        try {
            p.load(new FileReader("ID=Zone.txt"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        Set<Entry<Object, Object>> entrySet = p.entrySet();

        // 遍歷地區碼文件
        for (Entry<Object, Object> entry : entrySet) {
            count++;
            // 匹配身份證所屬區域
            if (num == count) {
                str1 = (String) entry.getKey();// 地區碼
                zone = (String) entry.getValue();// 獲取地區
                break;
            }
        }
        System.out.println(str1 + ":" + zone);

        // 獲取年份
        Calendar cal = Calendar.getInstance();
        // 獲取現在年份
        int year = cal.get(cal.YEAR);
        // 獲取150年前到現在的年份
        String str2 = Integer.toString(year - ra.nextInt(151));

        // 獲取月份
        String str3 = "";
        int month = ra.nextInt(12) + 1;
        if (month < 10) {
            str3 = "0" + Integer.toString(month);
        } else {
            str3 = Integer.toString(month);
        }

        // 獲取天
        String str4 = "";
        int day = ra.nextInt(31) + 1;
        if (day < 10) {
            str4 = "0" + Integer.toString(day);
        } else {
            str4 = Integer.toString(day);
        }

        // 判斷生成日期是否符合規則
        if (day > 28 && !isDate(year, month, day)) {
            System.out.println(year + ":" + month + ":" + day);
            // 重新賦值天數
            str4 = Integer.toString(day - 3);
            System.out.println("日期-天:" + str4);
        }

        // 獲取3位隨機數
        String str5 = "";
        int ran3 = ra.nextInt(1000);
        if (ran3 < 10) {
            str5 = "00" + Integer.toString(ran3);
        } else if (ran3 < 100) {
            str5 = "0" + Integer.toString(ran3);
        } else {
            str5 = Integer.toString(ran3);

        }

        // 獲取校驗碼
        // 獲取加權後的總和
        String id = str1 + str2 + str3 + str4 + str5;// 前17位ID
        // 獲取加權碼wi:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
        int[] wi = new int[17];
        for (int i = 1; i < 18; i++) {
            // 獲取加權數字
            int winum = (int) (Math.pow(2, i) % 11);
            // 將加權數反向存入數組
            wi[wi.length - i] = winum;
        }
        // 獲取加權後的總和
        int sum = 0;
        for (int i = 0; i < wi.length; i++) {
            // 獲取身份證前17位的每一位,轉換爲數字
            int j = Integer.parseInt(id.substring(i, i + 1));
            // 獲取加權後所得的和
            sum += (j * wi[i]);
        }
        // 匹配校驗碼
        String Ai = "10x987654342";
        // 獲取驗證碼索引:
        int index = sum % 11;
        String str6 = Ai.substring(index, index + 1);// 校驗碼

        // 輸出身份證
        System.out.println(id + str6);
    }

    // 進一步日期判斷
    public static boolean isDate(int year, int month, int day) {// day=29|30|31
        // 日期口訣: 一三五七八十臘(12月),三十一天永不差;平年二月二十八;閏年二月把一加 ;四六九冬(11月)三十日
        // 閏年:四年一閏,百年不閏,四百年再閏.
        if (month == 2) {// 當月份=2時
            if (day == 29 && (year % 4 == 0 && year % 100 != 0 | year % 400 == 0))
                return true;
            // 是2月非閏年
            return false;
        }
        // 天數是31天,月份卻是:4|6|9|11
        if (day == 31 && (month == 4 || month == 6 || month == 9 || month == 11))
            return false;
        // 其它正常情況
        return true;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章