Проверка номера — это последовательность дешёвых арифметических и текстовых операций, которая отвечает на один узкий вопрос: не противоречит ли строка сама себе. Ниже разберём, из каких трёх уровней складывается такая проверка, почему порядок уровней важнее их содержания, чем отличаются четыре возможных вывода и как объяснить результат человеку, не вводя его в заблуждение.
Что такое проверка номера?
У любой длинной последовательности знаков есть слабое место: тот, кто её набирает, рано или поздно ошибётся. Один знак заменится соседним на клавиатуре, два знака поменяются местами, лишний знак проскочит из буфера обмена. Ловить такие ошибки дорого, а не ловить — ещё дороже, потому что неверная строка уедет дальше по цепочке и всплывёт там, где исправлять её уже некому.
Самое дешёвое решение придумали задолго до появления компьютеров: последний знак номера вычисляется из всех остальных по опубликованному правилу. Если при пересчёте получается тот же знак, строка внутренне согласована. Если нет — где-то в ней ошибка. Для примера представим вымышленный номер из нескольких цифр, где последняя цифра равна остатку от деления суммы предыдущих на десять: последовательность два, четыре, шесть, восемь и ноль сходится, а замена любой цифры в середине — уже нет. Этот пример придуман здесь только для объяснения и не описывает ни одну настоящую систему нумерации.
Проверка номера не спрашивает ни у кого разрешения и не требует обмена данными: она выполняется на той же машине, где введена строка, и занимает доли мгновения. Именно поэтому такие проверки стоят на входе почти везде, где человек заводит длинный идентификатор руками.
Три слоя: набор символов, длина, контрольная цифра
Каждый уровень отвечает на собственный вопрос, и наборы пойманных ошибок у них почти не пересекаются.
- Набор символов. Разрешены ли в этой позиции цифры, латинские буквы, и то и другое? Посторонний знак внутри строки — самая грубая и самая заметная ошибка.
- Длина. Сколько знаков должно остаться после удаления разделителей? Слишком короткая или слишком длинная строка отсекается здесь, и ни одна арифметика дальше не нужна.
- Контрольная цифра. Сходятся ли последний знак или два последних с остальной частью по опубликованному правилу? Это единственный уровень, который вообще что-то говорит о согласованности значений.
Между собой уровни различаются не строгостью, а тем, что именно они способны заметить. Проверка набора символов не увидит перестановки двух цифр, потому что перестановка не меняет состав строки. Проверка длины не увидит опечатки внутри, если число знаков сохранилось. А контрольная цифра, наоборот, ничего не знает о допустимой длине и спокойно пропустит строку, у которой отрезали половину знаков, если её пересчитать заново. Практический вывод простой: три уровня работают только вместе, по отдельности каждый из них слаб.
Почему порядок уровней важнее их содержания
Соблазнительно начать с самого умного уровня — сразу посчитать контрольную цифру, ведь это интереснее всего. На практике такой порядок даёт бессмысленные и даже вредные ответы.
Причина в том, что арифметика контрольной цифры определена только для строки правильного состава и правильной длины. Если подать ей строку с посторонним знаком посередине, правило не сработает так, как задумывал автор системы нумерации, и вывод получится случайным. Пользователь увидит сообщение о неверной контрольной цифре и пойдёт проверять цифры, хотя настоящая причина — опечатка в букве.
Правильная последовательность выглядит так. Сначала нормализация: убираются разделители, выравнивается регистр. Затем проверка набора символов. Затем длина. И только в самом конце — контрольная цифра. Такая последовательность не случайна: каждый следующий уровень опирается на гарантии, которые дал предыдущий. После проверки состава известно, что все знаки принадлежат допустимому набору и с ними можно работать как с цифрами. После проверки длины известно, что правило контрольной цифры вообще применимо к этой строке.
Почему совпадение формата не означает, что номер принадлежит кому-то?
Это самая частая путаница в теме, и она дорого обходится. Контрольная цифра подтверждает только одно: строка не противоречит сама себе. Она не сообщает, выдавал ли кто-нибудь такой номер, закреплён ли он за человеком или организацией, действует ли он сейчас и можно ли им пользоваться.
Причина не в слабости конкретного алгоритма, а в самой природе проверки. Правило вычисления открыто, и это принципиально: оно должно быть открытым, иначе проверять номера могли бы только те, кто выпускает их. Но из открытости следует, что любой, кто знает правило, может дописать согласованный последний знак к любому набору цифр за мгновение. Значит, согласованность — это не признак подлинности, а признак аккуратности записи.
Отсюда практическое правило для интерфейсов и отчётов: никогда не превращать результат проверки в утверждение о существовании. Формулировка «строка согласована» честна, «номер настоящий» — уже нет. А формулировка «этого номера не существует» неверна вдвойне, потому что отсутствие согласованности говорит лишь о наличии опечатки или о подделке, но не о том, зарегистрирован ли номер где-либо.
Один номер может подойти нескольким системам нумерации
Проверяя строку, мы обычно знаем, что это за номер, — но знаем из контекста, а не из самой строки. Алгоритм же видит только знаки. И тут выясняется неприятное: одна и та же последовательность нередко удовлетворяет сразу нескольким правилам.
Причин две. Первая — длина и состав: две системы нумерации разных стран вполне могут использовать один и тот же диапазон длин, и тогда строка подходит обеим по формальным признакам. Вторая — арифметика: правила разных систем иногда устроены настолько похоже, что строка, согласованная по одному, оказывается согласованной и по другому.
Правильное поведение инструмента в такой ситуации — перечислить все системы, под которые строка подходит, а не выбирать одну. Угадывание страны по номеру льстит интерфейсу, но вводит в заблуждение: пользователь видит один ответ там, где их несколько, и делает вывод, которого данные не поддерживают. Список кандидатов честнее и полезнее, особенно когда дальше номер должен уехать в проверку по конкретной системе. Случай, когда подходящего правила вообще не нашлось, разобран отдельно в материале про номера без контрольной цифры.
Нормализация: пробелы, дефисы и регистр
Прежде чем сравнивать и считать, строку приводят к одному виду. Человек набирает номер так, как ему удобно: с пробелами между группами, с дефисами, точками, косыми чертами, иногда с буквами в другом регистре. Для правил нумерации все эти знаки — украшение, а не часть номера.
Отсюда набор действий, которые делают все проверки одинаковыми: убрать разделители, привести буквы к одному регистру, отбросить невидимые знаки — неразрывные пробелы, знаки нулевой ширины и тот невидимый апостроф, который Excel добавляет перед длинной строкой, чтобы не превращать её в число. Последний пункт неочевиден, но на практике портит больше данных, чем все остальные вместе: строка выглядит правильной, а проверка упорно не сходится.
Отдельно стоит вопрос, показывать ли нормализованный вид пользователю. Ответ — показывать. Когда рядом с исходной строкой видно, что именно ушло и что осталось, споры вида «я вводил правильный номер» прекращаются сами собой. И ещё одна оговорка: нормализация устраняет различия в записи, но не ошибки ввода. Если разделитель стоял не там, где нужно, удаление разделителей этого не исправит.
Четыре разных вывода вместо двух
Итог проверки не сводится к «прошло» и «не прошло». Честных выводов четыре, и они не пересекаются.
| Что удалось выяснить | Смысл вывода | Что делать дальше |
|---|---|---|
| Контрольная цифра сходится | строка согласована по правилу системы | продолжить обработку, помня о смысловых проверках |
| Формат совпал, цифра не сходится | строка противоречит сама себе | попросить перепроверить ввод, искать опечатку |
| Алгоритма в системе нет | подтверждён только формат | не выдавать суждение о действительности |
| Подходящей системы нет | правила для строки отсутствуют | сказать, что правила нет, а не что номер ложный |
Эти четыре состояния различаются не оттенком формулировки, а действием, которое за ними следует. Первое позволяет двигаться дальше. Второе указывает на конкретную задачу для пользователя. Третье требует честно признать границу возможного. Четвёртое — вообще не про номер, а про неполноту наших правил. Смешивать их опасно: пользователь, которому сказали «недействителен» там, где правила не существует, пойдёт менять корректный номер.
Как устроить такую проверку разработчику
Первое решение лежит не в коде, а в проектировании: разделите проверку на независимые шаги, каждый из которых возвращает собственный ответ. Один шаг приводит строку к каноническому виду. Второй проверяет состав знаков. Третий — длину. Четвёртый считает контрольную цифру. Пятый собирает из ответов общий вывод. Пока шаги разделены, каждый можно протестировать отдельно, а сообщение об ошибке всегда указывает на конкретный слой.
Второе — не превращайте длинную строку в число. Большинство языков теряют знаки при преобразовании, ведущие нули исчезают, а очень длинные значения округляются. Со строкой нужно работать посимвольно, а не как со значением целиком.
Третье — описывайте системы нумерации данными, а не условиями в коде. Тогда одна и та же процедура сможет обслуживать десятки систем, а добавление новой не потребует правки логики. Как это выглядит в промышленном масштабе, когда строк не одна, а сотни тысяч, разобрано в статье про пакетную проверку номеров.
Четвёртое — проектируйте ответ сразу как структуру: список подошедших систем, отдельный вывод по каждой из них, нормализованное значение и человекочитаемое пояснение. Пока ответ остаётся одним булевым значением, вы неизбежно будете терять информацию, которую уже получили. Сравнить между собой разные семейства правил, по которым строятся такие системы, помогает обзор алгоритмов контрольной цифры.
Что делать дальше
Возьмите поле в своей форме, которое сейчас принимает длинный номер, и честно выпишите, на какой из четырёх вопросов оно на самом деле отвечает. Скорее всего, окажется, что проверка там или отсутствует, или смешивает формат с действительностью. Затем отправьте несколько строк в инструмент проверки, чтобы увидеть отдельно, как выглядит нормализованный номер, каким системам он подошёл и что именно вернула контрольная цифра.
После этого поправьте формулировки подсказок: у вас должно быть отдельное сообщение для несогласованной контрольной цифры, для отсутствия алгоритма и для случая, когда правило просто неизвестно. Синтетические примеры из этой статьи придуманы для объяснения устройства проверки и не являются настоящими номерами, а любой результат проверки описывает только согласованность строки, но не говорит ни о её владельце, ни о том, выдавалась ли она когда-либо.