Содержание

Алгоритм Луна на языке Go

Алгоритм Луна, или проверка mod 10, - это простой алгоритм контрольной суммы. Его используют для предварительной проверки идентификационных номеров: банковских карт, IMEI и других числовых кодов.

Важно понимать ограничение: алгоритм Луна не доказывает, что карта существует, что на ней есть деньги или что пользователь имеет право ей пользоваться. Он только отвечает на вопрос: "похоже ли это число на корректно составленный номер по правилу контрольной суммы?"

Это похоже на проверку орфографии в слове. Если слово написано с ошибкой, проверка может это заметить. Но если слово написано правильно, это еще не значит, что предложение правдивое.

Зачем нужна контрольная сумма

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

Алгоритм Луна хорош для учебных задач, потому что в нем есть:

  • обход строки справа налево;
  • работа с цифрами;
  • условное преобразование;
  • сумма;
  • проверка остатка от деления.

Правило алгоритма

Для проверки числа:

  1. Идем по цифрам справа налево.
  2. Самую правую цифру оставляем как есть.
  3. Каждую вторую цифру справа умножаем на 2.
  4. Если после умножения получилось число больше 9, вычитаем 9.
  5. Складываем все полученные цифры.
  6. Если сумма делится на 10 без остатка, число проходит проверку.

Почему "вычитаем 9"? Если цифра 8 умножилась на 2, получилось 16. Сумма цифр 1 + 6 = 7. То же самое даст 16 - 9 = 7. Для результатов от 10 до 18 это удобная короткая форма.

Пошаговый пример

Ввод:

4532015112830366

Идем справа налево:

4 5 3 2 0 1 5 1 1 2 8 3 0 3 6 6

Преобразуем каждую вторую цифру справа:

8 5 6 2 0 1 1 1 2 2 7 3 0 3 3 6

Сумма:

8 + 5 + 6 + 2 + 0 + 1 + 1 + 1 + 2 + 2 + 7 + 3 + 0 + 3 + 3 + 6 = 50

50 % 10 == 0, значит номер проходит проверку Луна.

Реализация в Go

func ValidLuhn(input string) bool { if input == "" { return false } sum := 0 double := false for i := len(input) - 1; i >= 0; i-- { ch := input[i] if ch < '0' || ch > '9' { return false } digit := int(ch - '0') if double { digit *= 2 if digit > 9 { digit -= 9 } } sum += digit double = !double } return sum%10 == 0 }

Здесь ch - '0' превращает ASCII-символ цифры в число. Например, '7' - '0' дает 7.

Флаг double говорит, нужно ли удвоить текущую цифру. Мы начинаем справа, поэтому для самой правой цифры double равен false.

Пробелы и дефисы

Пользователь может ввести номер так:

4532 0151 1283 0366

или так:

4532-0151-1283-0366

Можно заранее нормализовать строку:

func normalizeNumber(input string) string { var builder strings.Builder for _, r := range input { if r == ' ' || r == '-' { continue } builder.WriteRune(r) } return builder.String() }

После нормализации передайте результат в ValidLuhn.

Проверка длины

Алгоритм Луна сам по себе не знает, какая длина допустима для конкретного типа номера. Поэтому часто добавляют отдельную проверку:

number := normalizeNumber(input) if len(number) < 12 || len(number) > 19 { return false } return ValidLuhn(number)

Для разных предметных областей правила длины могут отличаться. Не смешивайте их с самим алгоритмом, если хотите оставить функцию универсальной.

Тесты

func TestValidLuhn(t *testing.T) { tests := []struct { name string input string want bool }{ {name: "valid", input: "4532015112830366", want: true}, {name: "invalid checksum", input: "4532015112830367", want: false}, {name: "letters", input: "4532abc", want: false}, {name: "empty", input: "", want: false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := ValidLuhn(tt.input) if got != tt.want { t.Fatalf("got %v, want %v", got, tt.want) } }) } }

Обратите внимание на пустую строку: без отдельной проверки сумма была бы 0, и 0 % 10 == 0. Для пользовательского ввода это нежелательно, поэтому функция сразу возвращает false.

Частые ошибки

  1. Идти слева направо и удваивать неправильные позиции.
  2. Забыть вычесть 9 после удвоения.
  3. Не проверять, что символ является цифрой.
  4. Смешать алгоритм Луна с правилами конкретной платежной системы.
  5. Считать, что прохождение Луна означает валидную карту.

Чеклист

  1. Номер нормализуется, если разрешены пробелы или дефисы.
  2. Все символы проверяются как цифры.
  3. Обход идет справа налево.
  4. Каждая вторая цифра справа удваивается.
  5. При результате больше 9 вычитается 9.
  6. Сумма проверяется через sum % 10 == 0.
  7. Длина проверяется отдельным правилом, если это нужно для формы.

Следующий шаг после статьи

Закрепите тему во вводном проекте без регистрации, а затем переходите к курсам.

Продолжить изучение

Выбери следующую статью по маршруту или углубись в смежную тему.

Похожие статьи