A função
Uma só função valida o CNPJ numérico e o alfanumérico. O segredo é que cada caractere entra no módulo 11 como ord(c) - 48: assim '0'..'9' viram 0..9 (retrocompatível) e 'A'..'Z' viram 17..42.
Python
import re
_W1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
_W2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
def _dv_cnpj(base: str, pesos) -> int:
soma = sum((ord(c) - 48) * p for c, p in zip(base, pesos))
resto = soma % 11
return 0 if resto < 2 else 11 - resto
def is_valid_cnpj(cnpj: str) -> bool: # numérico OU alfanumérico
cnpj = re.sub(r'[./-]', '', cnpj).upper()
if not re.fullmatch(r'[A-Z0-9]{12}\d{2}', cnpj) or cnpj == cnpj[0] * 14:
return False
d1 = _dv_cnpj(cnpj[:12], _W1)
d2 = _dv_cnpj(cnpj[:12] + str(d1), _W2)
return d1 == int(cnpj[12]) and d2 == int(cnpj[13])
is_valid_cnpj('11.222.333/0001-81') # True (numérico)
is_valid_cnpj('12ABC34501DE35') # True (alfanumérico, exemplo SERPRO)São 12 posições de base (que podem ter letras) mais 2 dígitos verificadores que continuam numéricos. Os pesos são os mesmos do numérico — só a conversão do caractere muda.
Por que o exemplo SERPRO confere
A base oficial 12ABC34501DE produz DV 35: no 1º dígito a soma dá 459 (resto 8 → 11 - 8 = 3) e no 2º a soma dá 424 (resto 6 → 11 - 6 = 5). A função acima reproduz exatamente isso. Detalhe do cálculo em calcular o dígito verificador alfanumérico.
publicidade
Cuidados
- Só maiúsculas. O alfanumérico não aceita minúsculas — por isso a função faz
.upper()antes de validar. - Os DV são sempre numéricos. A regex exige
\d{2}no fim: letra nos dois últimos é inválido. - No banco, use texto. Colunas
NUMERIC/BIGINTquebram com letras — guarde emCHAR(14)/VARCHAR. - Válido ≠ existe. A função confirma a matemática, não se a empresa está cadastrada na Receita.
Continue
Código verificado por execução, inclusive contra o exemplo oficial do SERPRO (12ABC34501DE → DV 35). Algoritmo módulo 11 com ASCII−48. Revisado em 06/2026.