Python: Uma função Pythônica para validar CNPJ
Seguindo a ideia do post anterior, onde mostrei uma solução para a validação de CPF, falarei hoje sobre a validação de CNPJ. Mas como o cálculo é bem parecido, vou destacar apenas as diferenças entre eles.
Para a validação do CPF, os pesos aplicados aos seus dígitos vão de 2 a 11. Para o CNPJ, os pesos vão de 2 a 9 e então reiniciamos os pesos (novamente em 2). E, assim como para o CPF, os pesos são aplicados da direita para a esquerda.
Vamos usar o CNPJ (gerado aleatoriamente) 90.306.453/0001-33 como exemplo.
Ao aplicarmos os pesos teremos as seguintes associações:
9 | 0 | 3 | 0 | 6 | 4 | 5 | 3 | 0 | 0 | 0 | 1 |
5 | 4 | 3 | 2 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 |
Sem contar o primeiro DV.
E
9 | 0 | 3 | 0 | 6 | 4 | 5 | 3 | 0 | 0 | 0 | 1 | 3 |
6 | 5 | 4 | 3 | 2 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 |
Contando o primeiro DV.
Como a partir da aplicação dos pesos o algoritmo é exatamente o mesmo ao do CPF, vamos direto para o código.
from itertools import cycle
LENGTH_CNPJ = 14
def is_cnpj_valido(cnpj: str) -> bool:
if len(cnpj) != LENGTH_CNPJ:
return False
if cnpj in (c * LENGTH_CNPJ for c in "1234567890"):
return False
cnpj_r = cnpj[::-1]
for i in range(2, 0, -1):
cnpj_enum = zip(cycle(range(2, 10)), cnpj_r[i:])
dv = sum(map(lambda x: int(x[1]) * x[0], cnpj_enum)) * 10 % 11
if cnpj_r[i - 1:i] != str(dv % 10):
return False
return True
if __name__ == "__main__":
print("CNPJs inválidos")
print(is_cnpj_valido("0"))
print(is_cnpj_valido("123456789012345"))
print(is_cnpj_valido("5" * LENGTH_CNPJ))
print(is_cnpj_valido("90306453000103"))
print(is_cnpj_valido("90306453000130"))
print("CNPJs válidos")
print(is_cnpj_valido("90306453000133"))
print(is_cnpj_valido("82671952000100"))
print(is_cnpj_valido("31049514000165"))
print(is_cnpj_valido("77437514000133"))
print(is_cnpj_valido("00059549000151"))
Temos apenas 3 diferenças entre os códigos de validação de CNPJ e CPF, que são:
1. A importação da função "cycle" do pacote "intertools"
2. O tamanho da constante que é 14 para CNPJ
3. O método da aplicação dos pesos.
Como são apenas estas as diferenças, e a importação e o tamanho da constante não precisam maiores explicações, vou explicar apenas a parte dos pesos. (Para a explicação do restante do algoritmo, acesse o post do CPF).
Para aplicar os pesos do CPF, nós fazemos uso da função "enumerate", porém não podemos fazer o uso da mesma função para o CNPJ, pois os pesos do CNPJ não são sequenciais, uma vez que a sequência é reiniciada ao atingir o valor 9.
Para atendermos esta particularidade, fazemos uso de 3 funções: "range", "cycle" e "zip". Como todas são funções que merecem posts específicos para explicá-las, vamos apenas resumir como elas agem no algoritmo.
A função range irá nos retornar um iterável que se inicia em 2 e termina em 9 (o 10 não é incluso).
Este iterável é recebido pela função cycle, que por sua vez devolve um objeto "itertools.cycle". Vamos dizer que esse objeto é tipo um "iterável infinito", pois se fizermos um "for" nele, o loop "nunca" será finalizado.
Por fim pegamos este "iterável infinito" e o iterável com os dígitos invertidos do CNPJ e passamos para a função zip. A função irá unir estes 2 iteráveis, limitando o resultado pelo tamanho do menor iterável (neste caso o CNPJ). Com isso teremos todos os dígitos do CNPJ com seus respectivos pesos aplicados, similar ao que a função enumerate faz com o CPF.
A partir daqui segue igual ao que é feito com o CPF.
0 comentários:
Postar um comentário