ГлавнаяБлогАлгоритм Луна: проверка кредитных карт на Python
Алгоритмы

Алгоритм Луна: проверка кредитных карт на Python

Алгоритм Луна — как проверить номер карты за 20 строк Python. Реализация, определение платёжной системы и ограничения метода. Читайте и применяйте!

Al
Редакция Algolitalgolit.ru
7 мин чтения1 сентября 2026 г.

Алгоритм Луна: как форма знает, что номер карты неверный?

Введите случайный 16-значный номер в любую платёжную форму — и он будет отклонён мгновенно, ещё до обращения к банку или сетевого запроса. Откуда форма знает? Это не магия и не поиск в базе данных. Это контрольная сумма 1954 года, называемая алгоритмом Луна, и вы можете реализовать её примерно в 20 строках кода. Давайте создадим валидатор кредитных карт с нуля и разберём, что он может — и, что важнее, что не может — вам сказать.

Идея: одна цифра проверяет все остальные

Последняя цифра каждого номера карты не является частью вашего счёта. Это контрольная цифра, вычисляемая из всех предыдущих цифр. Когда вы вводите номер карты, валидатор пересчитывает контрольную сумму и сравнивает. Одна опечатка — и математика перестаёт сходиться.

Ганс Петер Лун, исследователь IBM, разработал этот алгоритм для обнаружения двух самых распространённых человеческих ошибок:

  • Опечатки в одной цифре — например, ввод 4 вместо 7 (обнаруживается в 100% случаев)
  • Перестановка соседних цифр — например, ввод 54 вместо 45 (обнаруживается почти всегда; единственное исключение — перестановка 09 ↔ 90)

Вот и всё. Алгоритм никогда не задумывался как защита — он должен был ловить опечатки. Помните об этом.

Как это работает: пошагово

Возьмём номер, например, 4539 1488 0343 6467. Работаем справа налево:

  1. Удваиваем каждую вторую цифру (позиции 2, 4, 6… справа).
  2. Если удвоение даёт двузначное число (например, 8 × 2 = 16), складываем его цифры (1 + 6 = 7). Короткий способ: просто вычесть 9.
  3. Суммируем всё — и удвоенные, и неизменённые цифры.
  4. Если сумма делится на 10, номер корректен по Луну.

Почему вычитание 9? Потому что для любой удвоенной цифры d ≥ 10 сумма её цифр равна d - 9. 16 → 7, 18 → 9. Тот же результат без работы со строками.

Реализация на Python: 20 строк кода

Вот функция, которая проверяет номер карты по алгоритму Луна:

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 до сих пор ошибочно отклоняют такие карты.

Что алгоритм Луна НЕ проверяет (прочтите перед запуском)

Это ключевая часть для тех, кто создаёт реальные продукты:

  • Корректность по Луну ≠ существование карты. Алгоритм проверяет формат, а не существование. Номер 4111 1111 1111 1111 проходит проверку, но никому не принадлежит. Прохождение теста Луна означает лишь «опечаток не обнаружено».
  • Никакой защиты. Любой может сгенерировать миллионы корректных номеров в цикле. Это детектор опечаток, а не защита от мошенничества. Реальная проверка происходит при авторизации через платёжный процессор.
  • Никогда не логируйте и не сохраняйте введённые данные. Даже «неверные» попытки — это часто почти правильные номера, на один символ от реальной карты. По стандарту PCI-DSS, если сырые номера карт касаются ваших серверов, вы берёте на себя обязательства по соответствию, которые вам явно не нужны. Валидация на клиенте и токенизированный платёжный провайдер (Stripe, Adyen и т.п.) полностью исключают номера карт из вашей инфраструктуры.

Где ещё применяется алгоритм Луна

Не всё числовое использует Луна, но удивительно много: IMEI-номера телефонов, канадские номера социального страхования, некоторые национальные идентификационные схемы — всё это использует ту же контрольную сумму.

Практический вывод: примените это сейчас

Алгоритм Луна — отличный первый «реальный алгоритм» для изучения: он короткий, повсеместный и учит паттерну — контрольные суммы как дешёвое обнаружение ошибок, который встречается повсюду в вычислениях, от ISBN до сетевых пакетов. Прямо сейчас возьмите свой любимый номер карты (тестовый, конечно) и проверьте его с помощью нашей функции. Затем добавьте проверку в свой проект — это займёт пять минут, а сэкономит пользователям нервы.

Самый старый алгоритм в вашем продакшене? Готов поспорить, что что-то в вашем стеке старше высадки на Луну. 👇

#алгоритм Луна#проверка кредитных карт#Python#контрольная сумма
Al
Редакция Algolit

Пишем про алгоритмы, подготовку к собеседованиям и карьеру в IT — так, чтобы было понятно и полезно.

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →