Генерация IMEI в Python

Здравствуйте, я пытаюсь сделать функцию в Python для генерации действительных номеров IMEI, так что вот моя функция. Проверка IMEI использует алгоритм Luhn, поэтому я пытаюсь реализовать его в своем скрипте.

def getImei():
    num = ''
    suma = 0
    for i in range(0,13):
        digit = random.randrange(0,9)
        suma = suma + digit
        num = num + str(digit)

    suma = suma * 9
    digit = suma % 10
    num = num + str(digit)
    return num

Однако функция не может генерировать действительные номера IMEI. Я нашел статью в Википедии, в которой рассказывается, как создать контрольную цифру ( http://en.wikipedia.org/wiki/Luhn_algorithm).

Контрольная цифра (x) получается путем вычисления суммы цифр и последующего вычисления в 9 раз этого значения по модулю 10 (в форме уравнения (67 * 9 mod 10)). В форме алгоритма: 1. Вычислите сумму цифр (67). 2. Умножить на 9 (603). 3. Последняя цифра 3 - контрольная цифра.

Я что-то упустил или вики-то не так?

3 ответа

Решение

Обратите внимание, что числа в нечетных (с конца, начиная с 0) положениях удваиваются, поэтому вы должны добавить их в свой код, например, следующий код вернет контрольную сумму luhn:

def luhn_residue(digits):
    return sum(sum(divmod(int(d)*(1 + i%2), 10))
                 for i, d in enumerate(digits[::-1])) % 10

Вот (1 + i%2) множитель равен 2 для нечетных номеров и 1 даже для позиционирования. затем sum(divmod(..., 10)) возвращает сумму цифр для (возможно) двухзначного числа и сумму сумм внешней суммы в результате последовательности.

Вы можете использовать его для генерации правильных числовых последовательностей:

def getImei(N):
    part = ''.join(str(random.randrange(0,9)) for _ in range(N-1))
    res = luhn_residue('{}{}'.format(part, 0))
    return '{}{}'.format(part, -res%10)

Демо-версия:

>>> luhn_residue('79927398713')
0
>>> luhn_residue('05671564547361')
6
>>> luhn_residue(getImei(14))
0

Вы пропускаете шаг, где удваиваете все остальные цифры и берете их сумму, если результат больше 10. Из Википедии:

От самой правой цифры, которая является контрольной цифрой, двигаясь влево, удваивают значение каждой второй цифры; если произведение этой операции удвоения больше 9 (например, 7 * 2 = 14), то суммируйте числа продуктов (например, 10: 1 + 0 = 1, 14: 1 + 4 = 5).

Решение от @alko не работает для всех номеров IMEI: посмотрите этот список допустимых номеров IMEI (или номеров CC, который на самом деле одинаков).

Вот решение, которое работает:

def luhn_residue(digits):
    """ Lunh10 residue value """
    s = sum(d if (n % 2 == 1) else (0, 2, 4, 6, 8, 1, 3, 5, 7, 9)[d]
            for n, d in enumerate(map(int, reversed(digits))))
    return (10 - s % 10) % 10
Другие вопросы по тегам