Правила кодирования и проверка идентификационных номеров

Java исходный код продукт

предисловие

В соответствии со статьей 23 недавно пересмотренного «Закона Китайской Народной Республики об удостоверениях личности резидента», удостоверения личности резидента, полученные в соответствии с «Положением об удостоверениях личности резидента Китайской Народной Республики», перестанут использоваться с 1 января 2013 г. То есть удостоверение личности первого поколения было прекращено с 1 января 2013 г. Содержание этой статьи относится к удостоверению личности второго поколения.Если не указано иное, удостоверение личности, упомянутое в этой статье, относится к удостоверению личности второго поколения. карта.

Версия jdk, которую я сейчас использую, — 1.6.0_29, а версия Eclipse — Juno Release, идентификатор сборки 20120614-1722. Если не указано иное, весь код Java в этой статье основан на этом.

Эта статья содержит большое количество математических формул и кодов Java. Просмотр на мобильном терминале затруднен. Вы можете просматривать текстовое содержимое на мобильном терминале. Математические формулы и коды Java можно просматривать на терминале ПК. В то же время время рекомендуется подготовить бумагу и ручку для вычисления математических формул. Читатели с некоторым математическим образованием также могут проигнорировать этот совет.

Код Java, представленный в этой статье, написан автором построчно и многократно рассмотрен, чтобы быть в состоянии проложить путь, чтобы новички могли работать не покладая рук и продвигаться на следующий уровень на пути изучения Java. Содержание этой статьи, недостатки, приглашаю всех критиковать и исправлять.

лист регистраций изменений

номер версии Дата проверки Примечания к редакции
V0.1 2018/08/13 первый черновик
V1.0 2018/09/02 выпуск

использованная литература

  1. Закон об удостоверении личности резидента Китайской Народной Республики
  2. Национальный стандарт Китайской Народной Республики GB/T 2260-2007 Кодекс административного деления Китайской Народной Республики
  3. Национальный стандарт Китайской Народной Республики GB 11643-1999 Номер удостоверения личности гражданина
  4. Национальный стандарт Китайской Народной Республики GB/T 17710-1999 Кодовая система проверки обработки данных
  5. Национальный стандарт Китайской Народной Республики GB/T 17710-2008 Система контрольных символов технологии безопасности информационных технологий
  6. ISO 7064:1983 Data processing - Check character systems
  7. ISO/IEC 7064:2003 Information technology - Security techniques - Check character systems

Правила кодирования идентификационных номеров

Идентификационный номер состоит из 18 цифр, включая 17-значный код тела и 1-значный проверочный код.

  1. Первые 6 цифр представляют собой адресный код, который указывает код административной единицы места регистрации домохозяйства, который должен быть реализован в соответствии с национальным стандартом «Кодекс административной единицы Китайской Народной Республики» (GB/ Т2260);
  2. Цифры с 7-й по 14-ю — это дата рождения в формате ГГГГММДД;
  3. Биты с 15 по 17 являются порядковыми кодами, указывающими порядковые номера людей, родившихся в один и тот же год, месяц и день в пределах области, определяемой одним и тем же адресным кодом.Нечетное число порядкового кода присваивается мужчинам, а четные числа присваиваются женщинам, т. е. 17. Нечетные числа представляют мужчин, а четные числа представляют женщин;
  4. 18-я цифра — это контрольный код, который использует систему контрольных знаков ISO 7064:1983, MOD 11-2 Правила расчета объясняются в следующей главе.

Отличие удостоверения личности первого поколения от удостоверения личности второго поколения заключается в следующем:

  1. Идентификационная карта первого поколения состоит из 15 цифр, а идентификационная карта второго поколения - из 18 цифр;
  2. Дата рождения удостоверения личности первого поколения — в формате ГГММДД, а дата рождения удостоверения личности второго поколения — в формате ГГГГММДД;
  3. У ID-карты первого поколения нет кода подтверждения, а у ID-карты второго поколения есть код подтверждения.

Проверить правила расчета кода

Значение числового символа в каждой позиции номера удостоверения личности должно удовлетворять проверке по следующей формуле:
\sum_{i=1}^{18} \left ( a_{i} \times W_{i}\right ) \equiv 1 \pmod{11}

  • iУказывает числовые символы从右至左Серийный номер позиции, включая символы контрольного кода;
  • a_{i}представляет числовое значение символа в i-й позиции,a_{1}Это 18-значный контрольный код номера удостоверения личности;
  • W_{i}Представляет весовой коэффициент в i-й позиции, а формула расчета весового коэффициента выглядит следующим образом:W_{i} = 2^{i-1} \pmod{11}

Например:

Идентификационный номер автора — 370683198901117657, который проверяется по приведенной выше формуле.

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
ai × Wi 21 63 0 30 64 12 2 9 48 27 0 9 10 5 56 24 10 7

\sum_{i=1}^{18} \left ( a_{i} \times W_{i}\right ) = 397 \equiv 1 \pmod{11}

Вы можете использовать этот метод для подтверждения своего идентификационного номера.

После понимания формулы проверки номера удостоверения личности формула расчета кода проверки номера удостоверения личности может быть доказана в соответствии с теоремой сравнения:
\begin{align*} & \because W_{1} = 2^{1-1} \pmod{11} = 1 \pmod{11} = 1 \\ & \therefore a_{1} + \sum_{i=2}^{18} ( a_{i} \times W_{i} )\equiv 1 \pmod{11} \\ & \therefore a_{1} \pmod{11} + \sum_{i=2}^{18} ( a_{i} \times W_{i} ) \pmod{11} \equiv 1 \pmod{11} \\ & \therefore a_{1} \pmod{11} + \sum_{i=2}^{18} ( a_{i} \times W_{i} ) \pmod{11} \equiv 12 \pmod{11} \\ & \therefore a_{1} \pmod{11} \equiv ( 12 - \sum_{i=2}^{18} ( a_{i} \times W_{i} ) \pmod{11} ) \pmod{11} \\ & \because 0 \leqslant a_{1} \leqslant 10 \land a_{1} \in N \\ & \therefore a_{1} = ( 12 - \sum_{i=2}^{18} ( a_{i} \times W_{i} ) \pmod{11} ) \pmod{11} \end{align*}

когдаa_{1}Когда значение равно 10, оно представляется символом римской цифры X. Обратите внимание:是罗马数字X,不应理解为英文字母X.

практическое применение

В системе программного обеспечения финансовой индустрии широко используются сбор и проверка номеров удостоверений личности.

  1. Первые 6 цифр номера удостоверения личности могут собирать место регистрации домохозяйства клиента, просто импортируйте в базу данных код административной единицы, определенный в национальном стандарте GB/T 2260, и отобразите его в программе; но это следует отметить что код административного деления - раз в несколько дней.Годовое собрание пересматривается один раз.Судя по изданию 2007 г., находящемуся в руках автора, оно претерпело девять редакций в 1982, 1984, 1986, 1988, 1991, 1995, 1999, 2002 гг. и 2007. Механизм обновления резервирования;
  2. Идентификационный номер состоит из 7–14 цифр, в нем можно указать дату рождения, возраст и день рождения клиента;
  3. Номер удостоверения личности состоит из 17 цифр, и можно узнать пол клиента: нечетные числа указывают на мужчин, четные — на женщин;
  4. Каналы проверки идентификационного номера, независимо от того, была ли проверка успешной или нет, часто тарифицируются, например, каналы банка и Министерства общественной безопасности.Перед отправкой на эти каналы для проверки необходимо проверить длину, регулярное выражение и код проверки. ., что может соответствующим образом улучшить процент успешных подтверждений оплаты и сократить расходы; это также может улучшить взаимодействие с пользователем и своевременную обратную связь, когда пользователи вводят ошибки, не дожидаясь возврата результатов канала проверки.

Затем возьмите фактический код в качестве примера, чтобы проиллюстрировать метод проверки номера удостоверения личности. Во-первых, дайте регулярное выражение для идентификационного номера:

/**
 * 18位二代身份证号码的正则表达式
 */
public static final String REGEX_ID_NO_18 = "^"
        + "\\d{6}" // 6位地区码
        + "(18|19|([23]\\d))\\d{2}" // 年YYYY
        + "((0[1-9])|(10|11|12))" // 月MM
        + "(([0-2][1-9])|10|20|30|31)" // 日DD
        + "\\d{3}" // 3位顺序码
        + "[0-9Xx]" // 校验码
        + "$";

/**
 * 15位一代身份证号码的正则表达式
 */
public static final String REGEX_ID_NO_15 = "^"
        + "\\d{6}" // 6位地区码
        + "\\d{2}" // 年YYYY
        + "((0[1-9])|(10|11|12))" // 月MM
        + "(([0-2][1-9])|10|20|30|31)" // 日DD
        + "\\d{3}"// 3位顺序码
        + "$";

Подтвердить идентификационный номер:

/**
 * 校验身份证号码
 * 
 * <p>
 * 适用于18位的二代身份证号码
 * </p>
 * 
 * @param IDNo18 身份证号码
 * @return true - 校验通过<br>
 *         false - 校验不通过
 * @throws IllegalArgumentException 
 *             如果身份证号码为空或长度不为18位或不满足身份证号码组成规则
 *             <i>6位地址码+
 *             出生年月日YYYYMMDD+3位顺序码
 *             +0~9或X(x)校验码</i>
 */
public static boolean checkIDNo(String IDNo18) {
    // 校验身份证号码的长度
    if (!checkStrLength(IDNo18, 18)) {
        throw new IllegalArgumentException();
    }
    // 匹配身份证号码的正则表达式
    if (!regexMatch(IDNo18, REGEX_ID_NO_18)) {
        throw new IllegalArgumentException();
    }
    // 校验身份证号码的验证码
    return validateCheckNumber(IDNo18);
}

/**
 * 校验字符串长度
 * 
 * @param inputString 字符串
 * @param len 预期长度
 * @return true - 校验通过<br>
 *         false - 校验不通过
 */
private static boolean checkStrLength(String inputString, int len) {
    if (inputString == null || inputString.length() != len) {
        return false;
    }
    return true;
}

/**
 * 匹配正则表达式
 * 
 * @param inputString 字符串
 * @param regex 正则表达式
 * @return true - 校验通过<br>
 *         false - 校验不通过
 */
private static boolean regexMatch(String inputString, String regex) {
    return inputString.matches(regex);
}

/**
 * 校验码校验
 * <p>
 * 适用于18位的二代身份证号码
 * </p>
 * 
 * @param IDNo18 身份证号码
 * @return true - 校验通过<br>
 *         false - 校验不通过
 */
private static boolean validateCheckNumber(String IDNo18) {
    // 加权因子
    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];
    }
    // 校验位是X,则表示10
    if (IDNoArray[17] == 'X' || IDNoArray[17] == 'x') {
        sum += 10;
    } else {
        sum += Integer.parseInt(String.valueOf(IDNoArray[17]));
    }
    // 如果除11模1,则校验通过
    return sum % 11 == 1;
}

Вычислить контрольную сумму:

/**
 * 计算身份证号码的校验码
 * <p>
 * 适用于18位的二代身份证号码,身份证号码由17位本体码和1位校验码组成
 * </p>
 * 
 * @param masterNumber 本体码
 * @return 身份证号码
 * @throws IllegalArgumentException 
 *             如果本体码为空或长度不为17位或不满足本体码组成规则
 *             <i>6位地址码+
 *             出生年月日YYYYMMDD+3位顺序码</i>
 */
public static String computeIDNoCheckNumber(String masterNumber) {
    // 校验本体码的长度
    if (!checkStrLength(masterNumber, 17)) {
        throw new IllegalArgumentException();
    }
    // 匹配本体码的正则表达式
    if (!regexMatch(masterNumber, REGEX_MASTER_NUMBER)) {
        throw new IllegalArgumentException();
    }
    // 计算校验码
    String checkNumber = computeCheckNumber(masterNumber);
    // 返回本体码+校验码=完整的身份证号码
    return masterNumber + checkNumber;
}

/**
 * 计算校验码
 * <p>
 * 适用于18位的二代身份证号码
 * </p>
 * 
 * @param masterNumber 本体码
 * @return 校验码
 */
private static String computeCheckNumber(String masterNumber) {
    // 加权因子
    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];
    }
    // 根据同余定理得到的校验码数组
    String[] checkNumberArray = { "1", "0", "X", "9", "8", "7", "6", "5", "4",
            "3", "2" };
    // 得到校验码
    String checkNumber = checkNumberArray[sum % 11];
    // 返回校验码
    return checkNumber;
}

Хотя 15-значное удостоверение личности первого поколения было отключено, неизбежно необходимо обновить 15-значное удостоверение личности первого поколения до 18-значного удостоверения личности второго поколения.Пример кода выглядит следующим образом:

/**
 * 15位一代身份证号码升级18位二代身份证号码
 * <p>
 * 为15位的一代身份证号码增加年份的前2位和最后1位校验码
 * </p>
 * 
 * @param IDNo15 15位的一代身份证号码
 * @return 18位的二代身份证号码
 */
public static String updateIDNo15to18(String IDNo15) {
    // 校验身份证号码的长度
    if (!checkStrLength(IDNo15, 15)) {
        throw new IllegalArgumentException();
    }
    // 匹配身份证号码的正则表达式
    if (!regexMatch(IDNo15, REGEX_ID_NO_15)) {
        throw new IllegalArgumentException();
    }
    // 得到本体码,因一代身份证皆为19XX年生人,年份中增加19,组成4位
    String masterNumber = IDNo15.substring(0, 6) + "19" + IDNo15.substring(6);
    // 计算校验码
    String checkNumber = computeCheckNumber(masterNumber);
    // 返回本体码+校验码=完整的身份证号码
    return masterNumber + checkNumber;
}

Конгруэнтность

Определение конгруэнтности

Для данного положительного целого числа m, если два целых числа a и b удовлетворяют тому, что a-b делится на m, то есть(a-b)/mЕсли получено целое число, то говорят, что целые числа a и b конгруэнтны по модулю m, что обозначается какa \equiv b \pmod m.

Свойство конгруэнтности

  1. Рефлексивность:a \equiv a \pmod m;
  2. Симметрия: еслиa \equiv b \pmod m,ноb \equiv a \pmod m;
  3. Транзитивность: еслиa \equiv b \pmod m,b \equiv c \pmod m,ноa \equiv c \pmod m;
  4. Добавить конгруэнтность: еслиa \equiv b \pmod m,b \equiv d \pmod m,ноa \pm c \equiv b \pm d \pmod m;
  5. Конгруэнтное умножение: еслиa \equiv b \pmod m,c \equiv d \pmod m,ноac \equiv bd \pmod m.

В главе правил расчета контрольного кода используются следующие формулы
( a + b ) \pmod{m} = ( a \mod m + b \mod m ) \pmod{m}
Мы берем это как пример, чтобы доказать, что
\begin{align*} a = q_{1}m + r_{1} \\ b = q_{2}m + r_{2} \end{align*}
но
\begin{align*} ( a + b ) \pmod{m} &= ( q_{1}m + r_{1} + q_{2}m + r_{2} ) \pmod{m} \\ &= ( ( q_{1} + q_{2} ) m + r_{1} + r_{2} ) \pmod{m} \\ &= ( r_{1} + r_{2} ) \pmod{m} \\ &= ( a \mod m + b \mod m ) \pmod{m} \\ \end{align*}

проверить систему символов

Что касается системы контрольных знаков, то международный стандарт ISO 7064 имеет 2 версии, а именно ISO 7064: 1983 и ISO/IEC 7064: 2003. По содержанию, кроме настройки поверхности, разницы по сути нет. можно понимать как декларацию суверенитета IEC после его создания. Кроме того, существуют также две версии соответствующих национальных стандартов, а именно GB/T 17710-1999 и GB/T 17710-2008, которые в основном обеспечивают высокий уровень перевода международных стандартов и делают читателей плохо владеющими английским языком. могут испытать строгость разработки международных стандартов через национальные стандарты и извлечь из этого пользу.

В стандарте предусмотрены следующие системы контрольных символов, которые в основном покрывают повседневные потребности. ISO 7064, MOD 11-2, используемый для проверки идентификационного номера, является одним из них. В реальных проектах его можно выбрать по мере необходимости.

тип системы имя системы Область применения Количество и тип контрольных кодов числовое представление
чистая система ISO 7064, MOD 11-2 номер 1 цифра или приложение X 1
чистая система ISO 7064, MOD 37-2 буква и цифра 1 цифра или буква или приложение* 2
чистая система ISO 7064, MOD 97-10 номер 2 цифры 3
чистая система ISO 7064, MOD 661-26 письмо 2 буквы 4
чистая система ISO 7064, MOD 1271-36 буква и цифра 2 цифры или буквы 5
Гибридная система ISO 7064, MOD 11,10 номер 1 цифра 6
Гибридная система ISO 7064, MOD 27,26 письмо 1 буква 7
Гибридная система ISO 7064, MOD 37,36 буква и цифра 1 цифра или буква 8

Как видно из таблицы, проверьте системы символов, включая чистые системы и смешанные системы. Та, которая использует один модуль, называется чистой системой, первое число после MOD в названии системы — модуль, а второе число — основание; та, которая использует два модуля, называется смешанной системой, а два числа после MOD в имени системы Все по модулю.

чистая система

Чистые системы, в свою очередь, включают использование одного контрольного символа и использование двух контрольных символов. Чистая система, использующая один контрольный символ, по существу аналогична чистой системе, использующей два контрольных символа, оба подчиняются формуле проверки:
\sum_{i=1}^{n} ( a_{i} \times r^{i-1} ) \equiv 1 \pmod{M}

  • n- количество символов в строке, включая контрольный символ;
  • i- Выражать从右至左Позиционный индекс символа, включая символ контрольной суммы, т.е. самый правый символi=1;
  • a_{i}- представляет значение символа на i-й позиции;
  • r- мощность;
  • M- Модуль.

Однако чистая система, использующая один контрольный символ, и чистая система, использующая два контрольных символа, немного отличаются в том, как вычисляется контрольный символ:

  • Чисто систематическая формула расчета контрольного символа с использованием контрольного символа
    \begin{align*} & ( \sum_{i=2}^{n} ( a_{i} \times r^{i-1} ) + a_{1} ) \equiv 1 \pmod{M} \\ \Rightarrow & a_{1} = ( M + 1 - \sum_{i=2}^{n} ( a_{i} \times r^{i-1} ) \pmod{M} ) \pmod{M} \end{align*}
    вa_{1}является контрольным символом,r^{i-1}также можно использоватьW_{i}заменять,W_{i} = r^{i-1} \pmod{M}.

  • Формула расчета контрольного символа для чистой системы с использованием двух контрольных символов
    \begin{align*} & ( \sum_{i=3}^{n} ( a_{i} \times r^{i-1} ) + a_{2} \times r + a_{1} ) \equiv 1 \pmod{M} \\ & a_{2} \times r + a_{1} = ( M + 1 - \sum_{i=3}^{n} ( a_{i} \times r^{i-1} ) \pmod{M} ) \pmod{M} \\ \Rightarrow & a_{2} = ( ( M + 1 - \sum_{i=3}^{n} ( a_{i} \times r^{i-1} ) \pmod{M} ) \pmod{M} ) / r \\ & a_{1} = ( ( M + 1 - \sum_{i=3}^{n} ( a_{i} \times r^{i-1} ) \pmod{M} ) \pmod{M} ) \pmod{r} \end{align*}
    вa_{2}иa_{1}является контрольным символом,r^{i-1}также можно использоватьW_{i}заменять,W_{i} = r^{i-1} \pmod{M}.

Существует два основных метода расчета чистых систем: чистый систематический рекурсивный метод и чистый систематический полиномиальный метод:

  • рекурсия
    Рассчитывается слева направо:
    ( \cdots ((a_{n} \times r + a_{n-1}) \times r + a_{n-2}) \times r + \cdots + a_{1}) \equiv 1 \pmod M

  • полиномиальный метод
    использовать\sumФормула говорит:
    \sum_{i=1}^{n}(a_{i} \times r^{i-1} \pmod{M}) \equiv 1 \pmod M

Фактически расчет рекурсивным методом полностью расширен, и получается полиномиальный метод, поэтому два метода расчета дают одинаковый результат.

Гибридная система

Гибридные системы используют контрольный символ и следуют формуле проверки:
( \cdots ((((((M+a_{n})||_{M}\times 2)|_{(M+1)}+a_{n-1})||_{M}\times 2)|_{(M+1)}+ \cdots + a_{i})||_{M}\times 2)|_{(M+1)} \cdots +a_{1})||_{M}=1

  • n- количество символов в строке, включая контрольный символ;
  • i- Выражать从右至左Позиционный индекс символа, включая символ контрольной суммы, т.е. самый правый символi=1;
  • a_{i}- представляет значение символа на i-й позиции;
  • Mи(M+1)- два по модулю;
  • ||_{M}- разделить наMПосле остатка, если его значение равно 0, используйтеMзаменять;
  • |_{(M+1)}- разделить на(M+1)После остатка, после вышеуказанной обработки, остаток никогда не будет равен 0.

Приведенная выше формула сама по себе является рекурсивным методом и не может быть расширена, поэтому гибридная система поддерживает только расчет рекурсивным методом и не поддерживает полиномиальный метод.

Наконец, прикрепите код, который всем нравится.

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