Grupos exclusivos de desconto no WhatsApp — Faca parte agora! Participar

Como validar CNPJ alfanumérico em Python

Função pronta em Python 3 para validar o novo CNPJ alfanumérico e calcular os dígitos verificadores, com uso em Django, Flask, pandas e teste com pytest.

Como validar CNPJ alfanumérico em Python

Quer validar o novo CNPJ alfanumérico em Python sem depender de biblioteca externa? Este tutorial traz uma função pronta para checar o CNPJ e calcular os dígitos verificadores em Python 3, com notas de uso em Django, Flask e pandas, além de um teste rápido com pytest.

O que muda no CNPJ alfanumérico

A partir de julho de 2026, a Receita Federal passa a emitir o CNPJ alfanumérico (Instrução Normativa RFB nº 2.229/2024). Ele mantém as 14 posições e a mesma máscara XX.XXX.XXX/XXXX-DD, mas as 12 primeiras posições (raiz + ordem) passam a aceitar letras maiúsculas A–Z e dígitos 0–9. Os dois dígitos verificadores continuam numéricos. Os CNPJs numéricos atuais não mudam e seguem válidos, convivendo com os novos — seu código precisa aceitar os dois formatos. Veja o panorama completo no nosso guia de implementação do CNPJ alfanumérico.

Validando CNPJ alfanumérico em Python

A função abaixo é autossuficiente: usa apenas o módulo re da biblioteca padrão. Ela normaliza a entrada (remove máscara e força maiúsculas), confere o formato (12 posições alfanuméricas + 2 dígitos), descarta a base zerada e compara os dígitos verificadores calculados com os informados. Copie como está:

Python
import re

PESO1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
PESO2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]

def normalizar(s: str) -> str:
    return re.sub(r'[^A-Z0-9]', '', (s or '').upper())

def _digito(base: str, pesos: list[int]) -> int:
    soma = sum((ord(base[i]) - 48) * pesos[i] for i in range(len(base)))
    resto = soma % 11
    return 0 if resto < 2 else 11 - resto

def calcular_dv(base12: str) -> str:
    d1 = _digito(base12, PESO1)
    d2 = _digito(base12 + str(d1), PESO2)
    return f'{d1}{d2}'

def validar_cnpj(cnpj: str) -> bool:
    c = normalizar(cnpj)
    if not re.match(r'^[A-Z0-9]{12}[0-9]{2}$', c):
        return False
    if re.match(r'^0{12}', c):
        return False
    return calcular_dv(c[:12]) == c[12:]

# validar_cnpj('12.ABC.345/01DE-35')  # True

Repare que validar_cnpj aceita a entrada com ou sem máscara, porque normalizar remove tudo que não for letra ou número antes de checar o formato.

Calculando os dígitos verificadores

Se você precisa gerar o CNPJ (e não só validar), use calcular_dv diretamente, passando as 12 primeiras posições. O primeiro dígito sai do peso PESO1 sobre as 12 posições; o segundo sai do PESO2 sobre as 12 posições mais o primeiro dígito. A regra do resto é a clássica do módulo 11: resto = soma % 11 e dv = 0 se resto < 2, senão 11 - resto. Veja em ação:

Python
>>> calcular_dv('12ABC34501DE')
'35'
>>> validar_cnpj('12.ABC.345/01DE-35')
True
>>> validar_cnpj('11.222.333/0001-81')  # numérico antigo, ainda válido
True
>>> validar_cnpj('12.ABC.345/01DE-34')  # DV errado
False

Usando em Django, Flask e pandas

Em Django, embrulhe a função em um validador de campo, levantando ValidationError quando validar_cnpj retornar False; aplique-o em models.CharField(validators=[...]) — nunca use campo inteiro para guardar CNPJ. Em Flask, chame validar_cnpj no handler ou num validador do WTForms antes de persistir. Para pandas, dá para limpar e checar uma coluna inteira de uma vez:

Python
import pandas as pd

df['cnpj_limpo'] = df['cnpj'].map(normalizar)
df['cnpj_valido'] = df['cnpj'].map(validar_cnpj)

# só as linhas com CNPJ inválido
invalidos = df[~df['cnpj_valido']]

Como testar

Resumo rápido
  • Copie as funções normalizar, _digito, calcular_dv e validar_cnpj para um módulo do seu projeto.
  • Valide com e sem máscara — a normalização cuida disso.
  • Confirme com os vetores oficiais abaixo (válidos e inválidos).
  • Gere massa de teste com o nosso gerador de CNPJ alfanumérico e confira no validador de CNPJ alfanumérico.
CNPJTipoEsperado
12.ABC.345/01DE-35Alfanumérico (filial)Válido
XP.TO1.234/0001-20Alfanumérico (matriz)Válido
9F.8E7.D6C/0001-36Alfanumérico (matriz)Válido
A1.B2C.3D4/E5F6-68Alfanumérico (filial)Válido
ZZ.ZZ0.001/AAAA-41AlfanuméricoVálido
2W.7H9.KQ5/R3T8-19AlfanuméricoVálido
11.222.333/0001-81Numérico clássicoVálido
12.ABC.345/01DE-34DV erradoInválido

Para automatizar, um teste curto com pytest resolve:

Python
import pytest
from cnpj import validar_cnpj, calcular_dv

@pytest.mark.parametrize('cnpj', [
    '12.ABC.345/01DE-35',
    'XP.TO1.234/0001-20',
    '9F.8E7.D6C/0001-36',
    'A1.B2C.3D4/E5F6-68',
    'ZZ.ZZ0.001/AAAA-41',
    '2W.7H9.KQ5/R3T8-19',
    '11.222.333/0001-81',
])
def test_validos(cnpj):
    assert validar_cnpj(cnpj) is True

def test_dv_errado():
    assert validar_cnpj('12.ABC.345/01DE-34') is False

def test_calcular_dv():
    assert calcular_dv('12ABC34501DE') == '35'

Perguntas frequentes

Preciso de alguma biblioteca para validar CNPJ alfanumérico em Python?

Não. A função usa apenas o módulo re, que já vem na biblioteca padrão do Python 3. Basta copiar o código para o seu projeto.

A mesma função valida os CNPJs numéricos antigos?

Sim. O algoritmo é o mesmo módulo 11, e dígitos numéricos são um caso particular do cálculo com ord(c) - 48. Por isso 11.222.333/0001-81 continua retornando True.

Como integro isso a um formulário Django ou Flask?

Embrulhe validar_cnpj em um validador: no Django, levante ValidationError quando retornar False e use no CharField; no Flask/WTForms, faça a mesma checagem num validador customizado. Guarde sempre como texto em maiúsculas.

Posso validar uma planilha inteira com pandas?

Sim. Use df['cnpj'].map(validar_cnpj) para marcar válidos e inválidos, e df['cnpj'].map(normalizar) para padronizar a coluna. Leia o arquivo com dtype=str para preservar zeros à esquerda.

Veja também as versões em JavaScript e Java deste mesmo algoritmo.

Fontes: Receita Federal (IN RFB 2.229/2024) e nota técnica do Serpro sobre o CNPJ alfanumérico.

Assistente PP
Assistente PP
Online agora
Powered by Primeira Solução