Алгоритм Луна — как проверить номер карты за 20 строк Python. Реализация, определение платёжной системы и ограничения метода. Читайте и применяйте!
Введите случайный 16-значный номер в любую платёжную форму — и он будет отклонён мгновенно, ещё до обращения к банку или сетевого запроса. Откуда форма знает? Это не магия и не поиск в базе данных. Это контрольная сумма 1954 года, называемая алгоритмом Луна, и вы можете реализовать её примерно в 20 строках кода. Давайте создадим валидатор кредитных карт с нуля и разберём, что он может — и, что важнее, что не может — вам сказать.
Последняя цифра каждого номера карты не является частью вашего счёта. Это контрольная цифра, вычисляемая из всех предыдущих цифр. Когда вы вводите номер карты, валидатор пересчитывает контрольную сумму и сравнивает. Одна опечатка — и математика перестаёт сходиться.
Ганс Петер Лун, исследователь IBM, разработал этот алгоритм для обнаружения двух самых распространённых человеческих ошибок:
Вот и всё. Алгоритм никогда не задумывался как защита — он должен был ловить опечатки. Помните об этом.
Возьмём номер, например, 4539 1488 0343 6467. Работаем справа налево:
Почему вычитание 9? Потому что для любой удвоенной цифры d ≥ 10 сумма её цифр равна d - 9. 16 → 7, 18 → 9. Тот же результат без работы со строками.
Вот функция, которая проверяет номер карты по алгоритму Луна:
def luhn_check(card_number: str) -> bool:
# Убираем пробелы и дефисы
digits = card_number.replace(" ", "").replace("-", "")
# Проверяем, что остались только цифры и длина 12–19
if not digits.isdigit() or not (12 <= len(digits) <= 19):
return False
total = 0
should_double = False # последняя цифра не удваивается
# Идём справа налево
for char in reversed(digits):
d = int(char)
if should_double:
d *= 2
if d > 9:
d -= 9 # короткий способ сложения цифр
total += d
should_double = not should_double # переключаем флаг
return total % 10 == 0Проверим:
print(luhn_check("4539 1488 0343 6467")) # True (валидный тестовый номер)
print(luhn_check("4539 1488 0343 6468")) # False (одна цифра неверна)
print(luhn_check("4111 1111 1111 1111")) # True (классический тестовый номер Visa)Временная сложность — O(n), один проход и никаких лишних выделений памяти, кроме очищенной строки. Код выполняется мгновенно на каждом нажатии клавиши.
Первые цифры номера (IIN/BIN — идентификатор эмитента) указывают на платёжную систему, поэтому формы показывают логотипы Visa/Mastercard по мере ввода:
def card_network(digits: str) -> str:
# digits — строка цифр без пробелов
if digits.startswith("4"):
return "Visa"
if digits.startswith("5") and digits[1] in "12345":
return "Mastercard"
if digits.startswith("2") and (2221 <= int(digits[:4]) <= 2720):
return "Mastercard" # диапазон 2017 года
if digits.startswith("3") and digits[1] in "47":
return "Amex" # 15 цифр!
if digits.startswith("6011") or digits.startswith("65"):
return "Discover"
if digits.startswith("3") and (digits[1] in "068" or digits[:2] == "30"):
return "Diners Club"
if digits.startswith("35") and (digits[2] in "89" or digits[2:4] in ["30".."38"]):
return "JCB"
return "Unknown"Две детали, которые часто путают: Amex — 15 цифр, а не 16 (и группируется как 4-6-5, а не 4-4-4-4), и Mastercard добавила диапазон 2221–2720 в 2017 году — многие старые регулярные выражения на Stack Overflow до сих пор ошибочно отклоняют такие карты.
Это ключевая часть для тех, кто создаёт реальные продукты:
Не всё числовое использует Луна, но удивительно много: IMEI-номера телефонов, канадские номера социального страхования, некоторые национальные идентификационные схемы — всё это использует ту же контрольную сумму.
Алгоритм Луна — отличный первый «реальный алгоритм» для изучения: он короткий, повсеместный и учит паттерну — контрольные суммы как дешёвое обнаружение ошибок, который встречается повсюду в вычислениях, от ISBN до сетевых пакетов. Прямо сейчас возьмите свой любимый номер карты (тестовый, конечно) и проверьте его с помощью нашей функции. Затем добавьте проверку в свой проект — это займёт пять минут, а сэкономит пользователям нервы.
Самый старый алгоритм в вашем продакшене? Готов поспорить, что что-то в вашем стеке старше высадки на Луну. 👇
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →