Pitch: Python - validador e gerador de CPF e CNPJ
Fala galera, tudo bem? Em meus últimos projetos tenho que usar quase que frequentemente validadores de CPF e CNPJ. Já usei alguns validadores prontos que funcionam muito bem, mas que acabam não funcionando corretamente para algumas entradas de dados do usuário (temos que imaginar todas as possibilidades). Uso um algoritmo desenvolvido por mim. É simples, mas me atende no que eu preciso no dia a dia. Com ele podemos validar e também gerar dados para usar em testes. Subi esse validador no PyPi para ser mais cômodo para mim. Caso queiram usar ou contribuir com algo, segue abaixo o link do PyPi e do GitHub.
PyPi - https://pypi.org/project/c2validator/ GitHub - https://github.com/devguilhermecosta/c2validator
Não estou com tempo pra criar um PR agora, mas seguem algumas sugestões.
Para limpar a string, em vez de ter uma lista do que quer remover, é mais simples filtrar pelo que quer manter, já que é uma lista bem menor (apenas os dígitos de 0 a 9).
Ou seja,
import string
def __clear(string_chain: str) -> str:
# cria outra string apenas com os dígitos de 0 a 9
return ''.join(c for c in string_chain if c in string.digits)
Na verdade é questionável se uma string como "abc123xxx456,;.^789{$#@}09"
deveria ser considerada um CPF (afinal, estamos limpando todos os caracteres indesejados e verificando os números que sobraram). Talvez ele só devesse aceitar no máximo os separadores (ponto e hífen) em posições específicas, mas enfim...
Se bem que, como vc usa isso para fazer o cálculo dos dígitos verificadores, talvez seja mais simples já converter tudo para int
, em vez de criar outra string.
E o cálculo pode ser feito mais diretamente, não precisa separar em tantos métodos. E até o uso de reduce
eu acho desnecessário, pois um loop simples é mais que suficiente.
Fiz uma versão mais simplificada, mas que pode ser adaptada no seu código:
import string
# retorna uma lista com os dígitos presentes na string
def extrai_digitos(string_chain):
return list(int(c) for c in string_chain if c in string.digits)
def calcula_digito(multiplicador, digitos):
total = 0
for d in digitos:
if multiplicador >= 2:
total += d * multiplicador
multiplicador -= 1
else: break
resto = total % 11
if resto < 2:
return 0
else:
return 11 - resto
def validar_cpf(cpf):
digitos = extrai_digitos(cpf)
if len(digitos) != 11:
return False
# primeiro dígito não bate, CPF inválido
if digitos[9] != calcula_digito(10, digitos):
return False
# segundo dígito não bate, CPF inválido
if digitos[10] != calcula_digito(11, digitos):
return False
return True
string_chain = '123@#$%456&*()789-09'
print(validar_cpf(string_chain)) # True
Ah, também dá pra calcular ambos os dígitos verificadores em um único loop:
import string
# retorna uma lista com os dígitos presentes na string
def extrai_digitos(string_chain):
return list(int(c) for c in string_chain if c in string.digits)
def calcula_resto(resto):
if resto < 2:
return 0
return 11 - resto
def validar_cpf(cpf):
digitos = extrai_digitos(cpf)
if len(digitos) != 11:
return False
# no mesmo loop, calculo ambos os dígitos verificadores
total1 = total2 = 0
multiplicador = 11
for d in digitos:
if multiplicador >= 2:
if multiplicador >= 3:
total1 += d * (multiplicador - 1)
total2 += d * multiplicador
multiplicador -= 1
else: break
# CPF válido se os DV's batem
return digitos[9] == calcula_resto(total1 % 11) and digitos[10] == calcula_resto(total2 % 11)
string_chain = '123@#$%456&*()789-09'
print(validar_cpf(string_chain)) # True