Resposta ao Algoritmo de Luhn

No final da noite de hoje vi-me desafiado por um amigo que em seu artigo citou o Algoritmo de Luhn que consiste na validação de Dígitos Verificadores.

Dígito verificador é um meio de validação e autenticação de uma série númerica para que se evite fraudes e perdas de informações.
Não entrarei em detalhe sobre a descrição do algoritmo que foi bem apresentado pelo artigo anteriormente citado. Como o desafio apresentado era descobrir o erro relatado:

"...Adicione o primeiro número (dígito de verificação) ao somatório geral, que deve iniciar com zero...."

O que acontece é que o dígito verificador não entra no cálculo para verificação da autenticidade da série. Somente a título de curiosidade gostaria de acrescentar uma breve descrição sobre os dígitos que formam a série númerica nos cartões.

A série númerica dos cartões de créditos possuem dezesseis dígitos que especificam uma gama de informações relacionadas a operadora do cartão, a entidade emissora, informações da conta, etc.

Da esquerda para direita, os seis primeiros dígitos referenciam a entidade emissora. Sendo que, o primeiro identifica a atividade da empresa e possui a seguinte descrição:

1- 2. Companhia aérea
3. Empresa de viagens, entretenimento e American Express(era ligada a navegação)
4. Visa
5. MasterCard
6. Discover)
7. Petróleo
8. Telecomunicações
0- 9. Outras atividades
O último dígito é o verificador, foi o que nos levou a essa breve apresentação, e o restante são informações relacionadas a conta bancária dos clientes.

Apresentarei um código em Python que pedirá a entrada da série(obrigatório) e o dígito verificador(opcional) para verificação da autencidade. Caso o dígito informado for incorreto ou omitido será apresentado o dígito verificador.

Obs.: Neste código será considerado somente o primeiro caracter informado na parte relacionada ao dígito verificador. Qualquer outro caracter será desconsiderado para cálculo.
Código:
#!/usr/bin/env python

# Luhn algorithm
#
# AUTHOR: Jose Mauro da Silva Sandy - http://informacaocomdiversao.blogspot.com
#
# CONTACT: jmsandy _at_ gmail _dot_ com
#
# DATE: 2008-10-26
#
# More information about Luhn algorithm, visit:
# http://en.wikipedia.org/wiki/Luhn_algorithm
###############################################################################

import easygui
import math

def verify_card(number_card):
  """Performs the sum of digits"""

  # Converting the string to list
  card = list(number_card[0])

  # Reversing the positions's list
  card.reverse()
  sum = 0
  for index in range(len(card)):
      value = int(card[index])

      if(not math.fmod(index,2)):
          value *= 2

      if(value >= 10):
          value %= 10
          value += 1

      sum += value

  # Checking if the sum is divisible for 10
  mod = int(math.fmod(sum,10))

  # If mod_10 like 10, then mod_10 = 0
  if((mod >= 10) or (mod == 0)):
      mod_10 = 0

  else:
      mod_10 = (10 - mod)

  return mod_10

msg = "Enter with number's card: "
title = "Number's Card"

values_names = ["Number's Card", "Verify digit"]
values = []
values = easygui.multenterbox(msg, title, values_names)

# Converting the values received to integer
# If the value is found valid, show result
# Otherwise, show error message
try:
  int(values[0])

  if(values[1]):
      int(values[1])
      sum = verify_card(values)

      digit = int(values[1][0])
      # If the number's card is valid, show result
      # Otherwise, show the valid value
      if(sum == digit):
          type_card = {'1': "Companhia Aerea", '2': "Companhia Aerea",
          '3': "Empresa de viagens, entretenimento ou American Express",
          '4': "Visa", '5': "MasterCard", '6': "Rede Discover", '7': "Petroleo",
          '8': "Telecomunicacoes", '9': "Outras Atividades",
          '0': "Outras Atividades" }

          easygui.msgbox("Number's card valid - " + type_card.get(values[0][0]))

      else:
          s = str(sum)
          easygui.msgbox("Digit verifier invalid, should to be " + s[0])

  else:
      sum = verify_card(values)
      s = str(sum)

      easygui.msgbox("Digit verifier invalid, should to be " + s[0])

except:
  easygui.msgbox("Invalid Value!")
José Mauro da Silva Sandy

Leia

2 comentários:

  Lopes

26 de outubro de 2008 às 10:40

Salve, simpatia!

Gostei! Estendeu o assunto! Mas o erro encontrado está errado. Note: eu passei 2 algoritmos. O primeiro levava em consideração o DV, pois desejava validar o número passado. O segundo não levava em consideração, pois visava o cálculo do mesmo. Inclusive, nas referências que utilizei, só constava o algoritmo que leva em consideração o DV. O outro, eu adaptei.

Contudo, a postagem foi legal. Essa do primeiro dígito eu não sabia. Já quanto à codificação, tenho algumas ressalvas:

1. (mod == 0)? (not mod) seria mais elegante...
2. mod = int(math.fmod(sum,10)) não teria o mesmo resultado que mod %= 10? Tudo bem que, pelo que já li, a função fmod() tem uma precisão melhor, mas quando você a utiliza dentro de uma função int(), ela terá o seu valor truncado, perdendo o seu diferencial...
3. Acho que seria mais fácil você trabalhar com uma string de inteiros. Pelo que entendi, você recebe uma string e a transforma numa lista de caracteres, o que adiciona a linha value = int(card[index]) ao for. Trabalhar com uma lista de inteiros também facilitaria em for item in card: (lembra?!)
4. PEP8 Na cabeça: http://versaopropria.blogspot.com/2008/10/o-estilo-de-programao-pep8.html

Ainda há um erro lá que ninguém achou...
:D

  José Mauro

26 de outubro de 2008 às 21:12

Fala, Zé!

Inicialmente quanto ao erro não consegui achar, em sua postagem irei apresentar uma outra opção.

Agora vamos as ressalvas:
1) Quanto a legibilidade do código você tem completa razão é que eu estou me acostumando com isso...já melhorei bastante.
2) Na verdade eu não estou pegando o módulo do valor contido em mod, mod %= 10, e sim o módulo do valor contido em sum está sendo atribuido em mod. Poderia ser algo do tipo: mod = sum % 10
3) Resolvi trabalhar com string mais pelo fato de utilizar o módulo easygui e fiquei obrigado a mexer com string. Quanto ao for tinha pensado em algo: for index in range(0,len(list),2), para realizar a multiplicação de 2 em 2. De qualquer forma acredito que o fato de trabalhar com indice neste caso foi uma boa prática.
4) Com certerza e se você reparar aos poucos estou mudando meus hábitos.

E ao meu ver o erro pode ser......
[]s