preface

According to article 23 of the newly revised Law of the People’s Republic of China on Resident Identity Cards, resident identity cards obtained in accordance with the Regulations of the People’s Republic of China on Resident Identity Cards will cease to be used as of January 1, 2013. That is, the first-generation ID card has ceased to be used since January 1, 2013. This article applies to the second-generation ID card. Unless otherwise specified, all the id cards mentioned in this article refer to the second-generation ID card.

The author is currently using JDK version 1.6.0_29, Eclipse version is Juno Release, Build ID 20120614-1722. Unless otherwise noted, all of the Java code in this article is based on this.

This article contains a large number of mathematical formulas and Java codes, the browsing experience is poor on the mobile terminal, text content can be browseen on the mobile terminal, mathematical formulas and Java codes can be browseen on the PC terminal, at the same time, it is recommended to prepare a pen and paper for the calculation of mathematical formulas. Readers with some mathematical background should also ignore this advice.

The Java code provided in this article is written by the author line by line, repeatedly considered, in order to be able to throw a brick to attract jade, so that beginners can be tireless, in the Java learning road to a higher level. The content of this article, the inadequacy, welcome everyone’s criticism and correction.

A revision history

The version number The revision date Revision note
V0.1 2018/08/13 The first draft
V1.0 2018/09/02 release

The resources

  1. Law of the People’s Republic of China on Resident Identity Cards
  2. National standard of the People’s Republic of China GB/T 2260-2007 Code for administrative divisions of the People’s Republic of China
  3. National standard of the People’s Republic of China GB 11643-1999 Citizen id card number
  4. National standard OF the People’s Republic of China GB/T 17710-1999 Data processing check code system
  5. National standard OF the People’s Republic of China GB/T 17710-2008 Information technology Security technology verification character system
  6. ISO 7064:1983 Data processing – Check character systems
  7. ISO/IEC 7064:2003 Information technology – Security techniques – Check character systems

Code rules for id card numbers

The ID card number consists of 18 digits, consisting of a 17-digit ontology code and a 1-digit verification code.

  1. The first six digits are address codes, indicating the administrative division code of the place where the registered residence is located, which shall be implemented in accordance with the national standard of The Administrative Division Code of the People’s Republic of China (GB/T2260).
  2. The 7 to 14 digits are the date of birth in the YYYYMMDD format.
  3. Digits 15 to 17 are sequence codes, indicating the serial number of people born in the same year, month and day within the area identified by the same address code. The odd number of the sequence code is assigned to men, and the even number to women, that is, the 17th odd number represents men, and the even number represents women.
  4. The 18th bit is the check code, using ISO 7064:1983, MOD 11-2 check character system, calculation rules described in the next section.

The difference between the first-generation id card and the second-generation ID card lies in:

  1. The first generation id card is 15, the second generation ID card is 18;
  2. The birth date of the first-generation ID card is in the YYMMDD format, and the birth date of the second-generation ID card is in the YYYYMMDD format.
  3. The first-generation ID card has no verification code, while the second-generation ID card has a verification code.

Verification code calculation rules

The character values of each position in the ID card number shall meet the verification of the following formula:

  • Number characterFrom right to leftPosition sequence number including check code character;
  • Represents the number character value in position I,Is the 18th verification code of the ID card number;
  • Denotes the weighting factor at the ith position, and the formula for calculating the weighting factor is:

For example:

The author’s ID number is 370683198901117657, which is verified according to the above formula.

i 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
ai 3 7 0 6 8 3 1 9 8 9 0 1 1 1 7 6 5 7
Wi 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 1
aiX Wi 21 63 0 30 64 12 2 9 48 27 0 9 10 5 56 24 10 7

You can verify your ID number according to this method.

After knowing the verification formula of the ID card number, the calculation formula of the verification code of the ID card number can be proved according to the congruence theorem:

whenA value equal to 10 is represented by the Roman numeral character X. Note here:Is the Roman numeral X, should not be understood as an English letter X.

The practical application

In the financial industry software system, the collection and verification of id card number is widely used.

  1. The first 6 digits of the ID card number can collect the customer’s household registration place. You only need to import the administrative division code defined in the national standard GB/T 2260 into the database for mapping in the program. However, it should be noted that the administrative division code is revised every few years. According to the 2007 version of the author’s hand, it has been revised for nine times in 1982, 1984, 1986, 1988, 1991, 1995, 1999, 2002 and 2007, so the updating mechanism should be reserved.
  2. Id card number 7 to 14 digits, can collect customer’s date of birth, age, birthday;
  3. The id card number is 17 digits, and the customer’s gender can be collected. The odd number indicates male, and the even number indicates female.
  4. Id card number verification channels, regardless of whether the verification is successful or not, are often charged, such as the bank channel, the Ministry of Public Security channel, before sending to these channels to verify the length, regular expression, check code verification, can appropriately improve the success rate of fee verification, save costs; It can also improve the user experience by giving feedback when a user enters an error without waiting for the result of the validation channel to return.

Below, take the actual code as an example, explain the id card number check method. First, the regular expression of id card number is given:

Public static final String REGEX_ID_NO_18 = "^" + "\\d{6}" // 6-bit area code + "(18 19 | | ([23] \ \ d)) \ \ d {2}"/YYYY/years + "((0 [1-9]) | | | 11 (10))" / / MM + "(([0-2] [1-9]) 10 20 | | | | 30 31)" / / day DD + "\ \ d {3}" / / 3 bit sequence code + "[0-9XX]" // check code + "$"; Public static final String REGEX_ID_NO_15 = "^" + "\\d{6}" // 6-bit area code + "\\ D {2}" // year YYYY + "((0 [1-9]) | | | 11 (10))" / / MM + "(([0-2] [1-9]) 10 20 | | | | 30 31)" / / day DD + "\ \ d {3}" / / three sequence code + "$";Copy the code

Verification ID card Number:

/** * CHECK ID number ** < P > * This parameter applies to the 18-bit id number of the second generation * </p> ** @param IDNo18 ID number * @return true - Check passes <br> * false - Check fails * @throws IllegalArgumentException * If the ID card number is empty or not 18 digits long, or does not meet the ID card number composition rules * < I > 6-digit address code + * Birth year month Date YYYYMMDD+ 3-digit sequence code * + 0-9 or X(X) verification code </ I > */ public static Boolean checkIDNo(String IDNo18) {if (! checkStrLength(IDNo18, 18)) { throw new IllegalArgumentException(); } // Match the id number of the regular expression if (! regexMatch(IDNo18, REGEX_ID_NO_18)) { throw new IllegalArgumentException(); } return validateCheckNumber(IDNo18);} return validateCheckNumber(IDNo18); } /** * Verification string length ** @param inputString String * @param Len Expected length * @return true - Verification passed <br> * false - Verification failed */ private static  boolean checkStrLength(String inputString, int len) { if (inputString == null || inputString.length() ! = len) { return false; } return true; } /** * Matching regular expression ** @param inputString String * @param regex regular expression * @return true - Verification passed <br> * false - Verification failed */ private static boolean regexMatch(String inputString, String regex) { return inputString.matches(regex); } /** * Verification code Verification * < P > * Applies to 18-bit id number of the second generation * </ P > ** @param IDNo18 ID number * @return true - Verification passes <br> * false - Verification fails */ private The static Boolean validateCheckNumber (String IDNo18) {/ / weighted factor int [] W = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}; char[] IDNoArray = IDNo18.toCharArray(); int sum = 0; for (int i = 0; i < W.length; i++) { sum += Integer.parseInt(String.valueOf(IDNoArray[i])) * W[i]; } / / check digit is X, say 10 if (IDNoArray [17] = = 'X' | | IDNoArray [17] = = 'X') {sum + = 10; } else { sum += Integer.parseInt(String.valueOf(IDNoArray[17])); Return sum % 11 == 1; return sum % 11 == 1; }Copy the code

Calculate the check code:

/** * The verification code for calculating the ID card number * < P > * applies to the 18-bit second-generation ID card number, The ID card number consists of a 17-bit ontology code and a 1-bit verification code. * </ P > * * @param masterNumber Ontology code * @Return ID number * @throws IllegalArgumentException * If the ontology code is empty or not 17 digits long or does not meet the ontology code composition rules * < I > 6-bit address code + * Birth year month date YYYYMMDD+ 3-bit sequence code </ I > */ public static String computeIDNoCheckNumber(String) MasterNumber) {// Check the length of the ontology if (! checkStrLength(masterNumber, 17)) { throw new IllegalArgumentException(); } // The regular expression matching the ontology code if (! regexMatch(masterNumber, REGEX_MASTER_NUMBER)) { throw new IllegalArgumentException(); } // Check code String checkNumber = computeCheckNumber(masterNumber); Return masterNumber + checkNumber; return masterNumber + checkNumber; } /** * Calculation check code * < P > * Applies to the 18-bit second-generation ID card number * </ P > ** @param masterNumber * @return Check code */ private static String ComputeCheckNumber (String masterNumber) {// Weighting factor int[] W = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}; char[] masterNumberArray = masterNumber.toCharArray(); int sum = 0; for (int i = 0; i < W.length; i++) { sum += Integer.parseInt(String.valueOf(masterNumberArray[i])) * W[i]; } / / based on Chinese remainder theory to get the check code of the array with String [] checkNumberArray = {" 1 ", "0", "X", "9", "eight", "7", "6", "5", "4", "3", "2"}; String checkNumber = checkNumberArray[sum % 11]; // Return checkNumber; }Copy the code

Although the 15-bit first-generation ID card has been discontinued, it is inevitable to upgrade the 15-bit first-generation ID card to the 18-bit second-generation ID card. The code example is as follows:

/** * 15-bit first-generation ID upgrade 18-bit second-generation ID * < P > * Adds the first two bits and the last bit of the parity code for the 15-bit first-generation ID * </p> ** @param IDNo15 15-bit first-generation ID * @return Public static String updateIDNo15to18(String updateIDNo15) {public static String updateIDNo15to18(String updateIDNo15) { checkStrLength(IDNo15, 15)) { throw new IllegalArgumentException(); } // Match the id number of the regular expression if (! regexMatch(IDNo15, REGEX_ID_NO_15)) { throw new IllegalArgumentException(); String masterNumber = idNO15. substring(0, 6) + "19" + idNO15. substring(6); String checkNumber = computeCheckNumber(masterNumber); Return masterNumber + checkNumber; return masterNumber + checkNumber; }Copy the code

congruence

Definition of congruence

Given a positive integer m, if two integers a and b are such that a-b is divisible by m, i.eI get an integer, so I call the integers a and B congruent to modulo m, and I call that.

Properties of congruence

  1. Reflexivity:;
  2. Symmetry: if,;
  3. Transitivity: if.,;
  4. Congruence addition: if.,;
  5. Multiply by congruence: if.,.

The following formula is used in the section of verification code calculation rules



Let’s take that as an example. Let’s say





Check character system

On the verification character system, the international standard ISO 7064 has two versions, respectively ISO 7064:1983 and ISO/IEC 7064:2003, from the content, in addition to the surface adjustment, there is no difference in essence, I think it can be understood as IEC after the establishment of its work scope of sovereignty declaration. Therefore, there are two versions of corresponding national standards, respectively GB/T 17710-1999 and GB/T 17710-2008, which basically guarantee the high-level translation level of international standards, so that readers with poor English reading ability can experience the rigor of international standards through national standards and benefit from them.

In the standard, the following check character systems are provided, which basically cover daily needs. The verification of id numbers using ISO 7064, MOD 11-2, is one of them. In actual projects, it can be selected as needed.

System type The name of the system Scope of application Number and type of verification codes Numerical representation
Pure system ISO 7064, MOD 11-2 digital 1 digit number or append X 1
Pure system ISO 7064, MOD 37-2 An alphanumeric One digit or letter or appended character * 2
Pure system ISO 7064, MOD 97-10 digital 2 digits 3
Pure system ISO 7064, MOD 661-26 The letter Two letters 4
Pure system ISO 7064, MOD 1271-36 An alphanumeric Two digits or letters 5
Hybrid system ISO 7064, MOD 11, 10 digital 1 digit 6
Hybrid system ISO 7064, MOD 27, 26 The letter One letter 7
Hybrid system ISO 7064, 37 4 MOD An alphanumeric One digit or letter 8

As shown in the table, check character system, including pure system and mixed system. A system that uses a module is called a pure system, where the first number after MOD is the module and the second number is the cardinal number. A system that uses two modules is called a hybrid system, and the two numbers after the MOD in the system name are modules.

Pure system

Pure systems also include using one check character and using two check characters. A pure system using one check character is essentially the same as a pure system using two check characters, both obeying the check formula:

  • – The number of characters in the string, including verification characters;
  • From right to leftThe positional index of characters, including parity characters, that is, the rightmost character;
  • – represents the character value in position I;
  • – base;
  • – module.

It is just that a pure system using one check character is slightly different from a pure system using two check characters in the way the check character is computed:

  • A check character calculation formula for a pure system that uses a check character



    Among themIs the check character,You can also useInstead,.



  • Check character calculation formula for a pure system using two check characters



    Among themandIs the check character,You can also useInstead,.

Pure systems have two basic calculation methods, pure system recursive method and pure system polynomial method:

  • The recursive method

    Calculated from left to right:

  • Polynomial method

    useThe formula represents:

In fact, the recursive method is completely expanded, and the result is polynomial method, so both methods give the same result.

Hybrid system

Hybrid systems use a checksum character that follows the checksum formula:

  • – The number of characters in the string, including verification characters;
  • From right to leftThe positional index of characters, including parity characters, that is, the rightmost character;
  • – represents the character value in position I;
  • and– Two modules;
  • – divided byThe remainder after, if its value is 0, thenInstead of;
  • – divided byAnd the remainder, after that, will never be zero.

The above formula itself is a recursive method and cannot be expanded. Therefore, the hybrid system only supports the recursive method, not the polynomial method.

Finally, the code that everyone likes.

package com.godson.util;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * ISO7064工具类
 * <p>
 * 使用ISO7064规范中定义的校验字符系统进行字符串的校验以及生成校验字符
 * </p>
 * 
 */
public class ISO7064Util {

    /**
     * ISO7064规范中定义的校验字符系统
     * <p>
     * <li>ISO 7064, MOD 11-2使用 {@link #ISO_7064_MOD_11_2}表示
     * </li>
     * <li>ISO 7064, MOD 37-2使用{@link #ISO_7064_MOD_37_2}表示</li>
     * <li>ISO 7064, MOD 97-10使用{@link #ISO_7064_MOD_97_10}
     * 表示</li>
     * <li>
     * ISO 7064, MOD 661-26使用 {@link #ISO_7064_MOD_661_26}表示
     * </li>
     * <li>ISO 7064, MOD 1271-36使用
     * {@link #ISO_7064_MOD_1271_36}表示</li>
     * <li>ISO 7064, MOD 11,10使用
     * {@link #ISO_7064_MOD_11_HYBRID_10}表示</li>
     * <li>ISO 7064, MOD 27,26使用
     * {@link #ISO_7064_MOD_27_HYBRID_26}表示</li>
     * <li>ISO 7064, MOD 37,36使用
     * {@link #ISO_7064_MOD_37_HYBRID_36}表示</li>
     */
    public enum Designation {
        /** ISO 7064, MOD 11-2 */
        ISO_7064_MOD_11_2,
        /** ISO 7064, MOD 37-2 */
        ISO_7064_MOD_37_2,
        /** ISO 7064, MOD 97-10 */
        ISO_7064_MOD_97_10,
        /** ISO 7064, MOD 661-26 */
        ISO_7064_MOD_661_26,
        /** ISO 7064, MOD 1271-36 */
        ISO_7064_MOD_1271_36,
        /** ISO 7064, MOD 11,10 */
        ISO_7064_MOD_11_HYBRID_10,
        /** ISO 7064, MOD 27,26 */
        ISO_7064_MOD_27_HYBRID_26,
        /** ISO 7064, MOD 37,36 */
        ISO_7064_MOD_37_HYBRID_36
    }

    /**
     * 计算校验字符
     * 
     * @param withoutCheckCharacterString 不含校验字符的字符串
     * @param designation 校验字符系统
     * @return 校验字符
     * @throws IllegalArgumentException
     *             如果字符串不匹配对应校验字符系统的正则表达式
     */
    public static String computeCheckCharacter(
            String withoutCheckCharacterString, Designation designation) {
        // 检查字符串是否匹配对应校验字符系统的正则表达式
        if (!RegexMatcher.withoutCheckCharacterStringIsMatch(
                withoutCheckCharacterString, designation)) {
            throw new IllegalArgumentException();
        }
        // 计算校验字符
        return CheckCharacterComputor.compute(withoutCheckCharacterString,
                designation);
    }

    /**
     * 校验字符串
     * 
     * @param withCheckCharacterString 含校验字符的字符串
     * @param designation 校验字符系统
     * @return true - 校验通过<br>
     *         false-校验不通过
     * @throws IllegalArgumentException
     *             如果字符串不匹配对应校验字符系统的正则表达式
     */
    public static boolean checkString(String withCheckCharacterString,
            Designation designation) {
        // 检查字符串是否匹配对应校验字符系统的正则表达式
        if (!RegexMatcher.withCheckCharacterStringIsMatch(
                withCheckCharacterString, designation)) {
            throw new IllegalArgumentException();
        }
        // 校验字符串
        return CheckCharacterSystemValidator.validate(withCheckCharacterString,
                designation);
    }

    /**
     * 正则表达式匹配器
     * <p>
     * 检查字符串是否匹配对应校验字符系统的正则表达式
     * </p>
     * <table border="1">
     * <tr>
     * <th>系统名称</th>
     * <th>适用范围</th>
     * <th>校验码数目及类型</th>
     * </tr>
     * <tr>
     * <td>ISO 7064, MOD 11-2</td>
     * <td>数字</td>
     * <td>1位数字或附加符X</td>
     * </tr>
     * <tr>
     * <td>ISO 7064, MOD 37-2</td>
     * <td>字母数字</td>
     * <td>1位数字或字母或附加符*</td>
     * </tr>
     * <tr>
     * <td>ISO 7064, MOD 97-10</td>
     * <td>数字</td>
     * <td>2位数字</td>
     * </tr>
     * <tr>
     * <td>ISO 7064, MOD 661-26</td>
     * <td>字母</td>
     * <td>2位字母</td>
     * </tr>
     * <tr>
     * <td>ISO 7064, MOD 1271-36</td>
     * <td>字母数字</td>
     * <td>2位数字或字母</td>
     * </tr>
     * <tr>
     * <td>ISO 7064, MOD 11,10</td>
     * <td>数字</td>
     * <td>1位数字</td>
     * </tr>
     * <tr>
     * <td>ISO 7064, MOD 27,26</td>
     * <td>字母</td>
     * <td>1位字母</td>
     * </tr>
     * <tr>
     * <td>ISO 7064, MOD 37,36</td>
     * <td>字母数字</td>
     * <td>1位数字或字母</td>
     * </tr>
     * </table>
     */
    private static class RegexMatcher {

        /**
         * 检查不含校验字符的字符串是否匹配对应校验字符系统的正则表达式
         * 
         * @param withoutCheckCharacterString 不含校验字符的字符串
         * @param designation 校验字符系统
         * @return true - 匹配<br>
         *         false - 不匹配
         */
        static boolean withoutCheckCharacterStringIsMatch(
                String withoutCheckCharacterString, Designation designation) {
            return regexMatch(withoutCheckCharacterString,
                    REGEX_MAPPING_WITHOUT_CHECK_CHARACTER_STRING
                            .get(designation));
        }

        /**
         * 检查有校验字符的字符串是否匹配对应校验字符系统的正则表达式
         * 
         * @param withCheckCharacterString 含校验字符的字符串
         * @param designation 校验字符系统
         * @return true - 匹配<br>
         *         false - 不匹配
         */
        static boolean withCheckCharacterStringIsMatch(
                String withCheckCharacterString, Designation designation) {
            return regexMatch(withCheckCharacterString,
                    REGEX_MAPPING_WITH_CHECK_CHARACTER_STRING.get(designation));
        }

        /** 数字正则表达式 */
        static final String REGEX_NUMBERIC_STRINGS = "^[0-9]+$";
        /** 含补充校验字符X的数字正则表达式 */
        static final String REGEX_NUMBERIC_STRINGS_WITH_SUPPLEMENTARY_CHECK_CHARACTER = "^[0-9]+[0-9X]$";
        /** 字母正则表达式 */
        static final String REGEX_ALPHABETIC_STRINGS = "^[A-Z]+$";
        /** 字母数字正则表达式 */
        static final String REGEX_ALPHANUMBERIC_STRINGS = "^[0-9A-Z]+$";
        /** 含补充校验字符*的字母数字表达式 */
        static final String REGEX_ALPHANUMBERIC_STRINGS_WITH_SUPPLEMENTARY_CHECK_CHARACTER = "^[0-9A-Z]+[0-9A-Z*]$";

        /** 校验字符系统对应的正则表达式(不含校验字符) */
        @SuppressWarnings("serial")
        static final Map<Designation, String> REGEX_MAPPING_WITHOUT_CHECK_CHARACTER_STRING = new HashMap<Designation, String>() {
            {
                put(Designation.ISO_7064_MOD_11_2, REGEX_NUMBERIC_STRINGS);
                put(Designation.ISO_7064_MOD_37_2, REGEX_ALPHANUMBERIC_STRINGS);
                put(Designation.ISO_7064_MOD_97_10, REGEX_NUMBERIC_STRINGS);
                put(Designation.ISO_7064_MOD_661_26, REGEX_ALPHABETIC_STRINGS);
                put(Designation.ISO_7064_MOD_1271_36,
                        REGEX_ALPHANUMBERIC_STRINGS);
                put(Designation.ISO_7064_MOD_11_HYBRID_10,
                        REGEX_NUMBERIC_STRINGS);
                put(Designation.ISO_7064_MOD_27_HYBRID_26,
                        REGEX_ALPHABETIC_STRINGS);
                put(Designation.ISO_7064_MOD_37_HYBRID_36,
                        REGEX_ALPHANUMBERIC_STRINGS);
            }
        };

        /** 校验字符系统对应的正则表达式(含校验字符) */
        @SuppressWarnings("serial")
        static final Map<Designation, String> REGEX_MAPPING_WITH_CHECK_CHARACTER_STRING = new HashMap<Designation, String>() {
            {
                put(Designation.ISO_7064_MOD_11_2,
                        REGEX_NUMBERIC_STRINGS_WITH_SUPPLEMENTARY_CHECK_CHARACTER);
                put(Designation.ISO_7064_MOD_37_2,
                        REGEX_ALPHANUMBERIC_STRINGS_WITH_SUPPLEMENTARY_CHECK_CHARACTER);
                put(Designation.ISO_7064_MOD_97_10, REGEX_NUMBERIC_STRINGS);
                put(Designation.ISO_7064_MOD_661_26, REGEX_ALPHABETIC_STRINGS);
                put(Designation.ISO_7064_MOD_1271_36,
                        REGEX_ALPHANUMBERIC_STRINGS);
                put(Designation.ISO_7064_MOD_11_HYBRID_10,
                        REGEX_NUMBERIC_STRINGS);
                put(Designation.ISO_7064_MOD_27_HYBRID_26,
                        REGEX_ALPHABETIC_STRINGS);
                put(Designation.ISO_7064_MOD_37_HYBRID_36,
                        REGEX_ALPHANUMBERIC_STRINGS);
            }
        };

        static boolean regexMatch(String inputString, String regex) {
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(inputString);
            return matcher.matches();
        }
    }

    /** 适用于数字的校验字符系统的数值对应表 */
    private static final String[] NUMBERIC_STRINGS = { "0", "1", "2", "3", "4",
            "5", "6", "7", "8", "9", "X" };
    /** 适用于字母的校验字符系统的数值对应表 */
    private static final String[] ALPHABETIC_STRINGS = { "A", "B", "C", "D",
            "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
            "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
    /** 适用于字母数字的校验字符系统的数值对应表 */
    private static final String[] ALPHANUMBERIC_STRINGS = { "0", "1", "2", "3",
            "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G",
            "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
            "U", "V", "W", "X", "Y", "Z", "*" };

    /**
     * 校验字符系统验证器
     */
    private static class CheckCharacterSystemValidator {
        static boolean validate(String inputString, Designation designation) {
            switch (designation) {
                case ISO_7064_MOD_11_2:
                case ISO_7064_MOD_37_2:
                case ISO_7064_MOD_97_10:
                case ISO_7064_MOD_661_26:
                case ISO_7064_MOD_1271_36:
                    return validatePureSystem(inputString, designation);
                case ISO_7064_MOD_11_HYBRID_10:
                case ISO_7064_MOD_27_HYBRID_26:
                case ISO_7064_MOD_37_HYBRID_36:
                    return validateHybridSystem(inputString, designation);
                default:
                    return false;
            }
        }

        /**
         * 纯系统校验
         */
        static boolean validatePureSystem(String inputString,
                Designation designation) {
            int M = 0; // 模数
            int r = 0; // 基数
            List<String> mapping = null;
            switch (designation) {
                case ISO_7064_MOD_11_2:
                    M = 11;
                    r = 2;
                    mapping = Arrays.asList(NUMBERIC_STRINGS);
                    break;
                case ISO_7064_MOD_37_2:
                    M = 37;
                    r = 2;
                    mapping = Arrays.asList(ALPHANUMBERIC_STRINGS);
                    break;
                case ISO_7064_MOD_97_10:
                    M = 97;
                    r = 10;
                    mapping = Arrays.asList(NUMBERIC_STRINGS);
                    break;
                case ISO_7064_MOD_661_26:
                    M = 661;
                    r = 26;
                    mapping = Arrays.asList(ALPHABETIC_STRINGS);
                    break;
                case ISO_7064_MOD_1271_36:
                    M = 1271;
                    r = 36;
                    mapping = Arrays.asList(ALPHANUMBERIC_STRINGS);
                    break;
                default:
                    return false;
            }
            char[] strArray = inputString.toCharArray();
            int S = 0;
            int n = strArray.length;
            for (int i = 1; i <= n; i++) {
                // 注意这里不要使用Math的pow方法
                S += mapping.indexOf(String.valueOf(strArray[i - 1]))
                        * BigInteger.valueOf(r).pow(n - i)
                                .mod(BigInteger.valueOf(M)).intValue();
            }
            return S % M == 1;
        }

        /**
         * 混合系统校验
         */
        static boolean validateHybridSystem(String inputString,
                Designation designation) {
            int M = 0; // 模数1
            List<String> mapping = null;

            switch (designation) {
                case ISO_7064_MOD_11_HYBRID_10:
                    M = 10;
                    mapping = Arrays.asList(NUMBERIC_STRINGS);
                    break;
                case ISO_7064_MOD_27_HYBRID_26:
                    M = 26;
                    mapping = Arrays.asList(ALPHABETIC_STRINGS);
                    break;
                case ISO_7064_MOD_37_HYBRID_36:
                    M = 36;
                    mapping = Arrays.asList(ALPHANUMBERIC_STRINGS);
                    break;
                default:
                    return false;
            }
            int Mplus1 = M + 1; // 模数2
            char[] strArray = inputString.toCharArray();
            int S = M + mapping.indexOf(String.valueOf(strArray[0]));
            int P = 0;
            for (int i = 1; i < strArray.length; i++) {
                P = ((S % M == 0 ? M : S % M) * 2) % Mplus1;
                S = P + mapping.indexOf(String.valueOf(strArray[i]));
            }
            return S % M == 1;
        }
    }

    /**
     * 校验字符生成器
     */
    private static class CheckCharacterComputor {
        static String compute(String inputString, Designation designation) {
            switch (designation) {
                case ISO_7064_MOD_11_2:
                case ISO_7064_MOD_37_2:
                    return polynomialMethod4PureSystemWith1CheckChar(
                            inputString, designation);
                case ISO_7064_MOD_97_10:
                case ISO_7064_MOD_661_26:
                case ISO_7064_MOD_1271_36:
                    return polynomialMethod4PureSystemWith2CheckChar(
                            inputString, designation);
                case ISO_7064_MOD_11_HYBRID_10:
                case ISO_7064_MOD_27_HYBRID_26:
                case ISO_7064_MOD_37_HYBRID_36:
                    return recursiveMethod4HybridSystemWith1CheckChar(
                            inputString, designation);
                default:
                    return null;
            }
        }

        /**
         * 通过多项式法计算纯系统一位校验字符
         */
        static String polynomialMethod4PureSystemWith1CheckChar(String str,
                Designation designation) {
            int M = 0; // 模数
            int r = 0; // 基数
            List<String> mapping = null;
            switch (designation) {
                case ISO_7064_MOD_11_2:
                    M = 11;
                    r = 2;
                    mapping = Arrays.asList(NUMBERIC_STRINGS);
                    break;
                case ISO_7064_MOD_37_2:
                    M = 37;
                    r = 2;
                    mapping = Arrays.asList(ALPHANUMBERIC_STRINGS);
                    break;
                default:
                    break;
            }
            char[] strArray = str.toCharArray();
            int S = 0;
            int n = strArray.length + 1;
            for (int i = n; i >= 2; i--) {
                // 注意这里不要使用Math的pow方法
                S += mapping.indexOf(String.valueOf(strArray[n - i]))
                        * BigInteger.valueOf(r).pow(i - 1)
                                .mod(BigInteger.valueOf(M)).intValue();
            }
            return mapping.get((M + 1 - S % M) % M);
        }

        /**
         * 通过多项式法计算纯系统二位校验字符
         */
        static String polynomialMethod4PureSystemWith2CheckChar(String str,
                Designation designation) {
            int M = 0; // 模数
            int r = 0; // 基数
            List<String> mapping = null;
            switch (designation) {
                case ISO_7064_MOD_97_10:
                    M = 97;
                    r = 10;
                    mapping = Arrays.asList(NUMBERIC_STRINGS);
                    break;
                case ISO_7064_MOD_661_26:
                    M = 661;
                    r = 26;
                    mapping = Arrays.asList(ALPHABETIC_STRINGS);
                    break;
                case ISO_7064_MOD_1271_36:
                    M = 1271;
                    r = 36;
                    mapping = Arrays.asList(ALPHANUMBERIC_STRINGS);
                    break;
                default:
                    break;
            }
            char[] strArray = str.toCharArray();
            int S = 0;
            int n = strArray.length + 2;
            for (int i = n; i >= 3; i--) {
                // 注意这里不要使用Math的pow方法
                S += mapping.indexOf(String.valueOf(strArray[n - i]))
                        * BigInteger.valueOf(r).pow(i - 1)
                                .mod(BigInteger.valueOf(M)).intValue();
            }
            return mapping.get(((M + 1 - S % M) % M) / r)
                    + mapping.get(((M + 1 - S % M) % M) % r);
        }

        /**
         * 通过递归法法计算混合系统一位校验字符
         */
        static String recursiveMethod4HybridSystemWith1CheckChar(
                String inputString, Designation designation) {
            int M = 0; // 模数1
            List<String> mapping = null;
            switch (designation) {
                case ISO_7064_MOD_11_HYBRID_10:
                    M = 10;
                    mapping = Arrays.asList(NUMBERIC_STRINGS);
                    break;
                case ISO_7064_MOD_27_HYBRID_26:
                    M = 26;
                    mapping = Arrays.asList(ALPHABETIC_STRINGS);
                    break;
                case ISO_7064_MOD_37_HYBRID_36:
                    M = 36;
                    mapping = Arrays.asList(ALPHANUMBERIC_STRINGS);
                    break;
                default:
                    break;
            }
            int Mplus1 = M + 1; // 模数2
            char[] strArray = inputString.toCharArray();
            int S = 0;
            int P = M;
            int n = strArray.length + 1;
            for (int i = n; i >= 2; i--) {
                S = P + mapping.indexOf(String.valueOf(strArray[n - i]));
                P = ((S % M == 0 ? M : S % M) * 2) % Mplus1;
            }
            return mapping.get((M + 1 - P % M) % M);
        }
    }
}
Copy the code