Генерация 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