1

O Novo CNPJ Alfanumérico da Receita Federal: Como funciona o cálculo de validação e como adaptar seus sistemas

Se você trabalha com sistemas de faturamento, ERPs, gateways de pagamento ou formulários de cadastro de clientes, com certeza já notou o comunicado oficial da Receita Federal: a transição para o CNPJ Alfanumérico.

Com a iminente exaustão das combinações puramente numéricas de 14 dígitos, o novo padrão passa a aceitar letras e números nas primeiras 12 posições. Apenas os 2 últimos dígitos (os dígitos verificadores - DV) continuam estritamente numéricos.

Abaixo está uma explicação técnica detalhada de como a matemática do cálculo mudou e a implementação completa da função de validação pronta para colar no seu backend ou frontend.


1. O que muda na estrutura do CNPJ?

  • Formato Tradicional: 00.000.000/0000-00 (14 dígitos numéricos).
  • Novo Formato: XX.XXX.XXX/XXXX-00 (onde X pode ser qualquer número de 0 a 9 OU qualquer letra de A a Z em maiúsculo).
  • Os 2 Dígitos Verificadores: Permanecem sendo 2 números decimais calculados com base nas 12 posições anteriores.

Isso significa que expressões regulares antigas do tipo /^\d{2}\.\d{3}\.\d{3}\/\d{4}\-\d{2}$/ ou colunas de banco de dados do tipo BIGINT vão quebrar imediatamente.


2. A Matemática: Tabela ASCII e o Módulo 11 Ponderado

No CNPJ clássico, multiplicávamos cada dígito numérico por pesos decrescentes (5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2).

No padrão alfanumérico, a Receita Federal determinou a seguinte regra de conversão para transformar caracteres alfanuméricos em números antes da multiplicação:

Valor do Caractere=Coˊdigo ASCII do Caractere−48\text{Valor do Caractere} = \text{Código ASCII do Caractere} - 48

O que isso produz na prática?

  • Caracteres '0' a '9': Códigos ASCII 48 a 57.
    Valor=48−48=0ateˊ57−48=9\text{Valor} = 48 - 48 = \mathbf{0} \quad \text{até} \quad 57 - 48 = \mathbf{9}
    (Os números continuam valendo exatamente o seu próprio valor!)
  • Caracteres 'A' a 'Z': Códigos ASCII 65 a 90.
    Valor de ’A’=65−48=17\text{Valor de 'A'} = 65 - 48 = \mathbf{17}
    Valor de ’B’=66−48=18\text{Valor de 'B'} = 66 - 48 = \mathbf{18}
    Valor de ’Z’=90−48=42\text{Valor de 'Z'} = 90 - 48 = \mathbf{42}

Após converter cada caractere para o seu valor inteiro equivalente, aplica-se o mesmo algoritmo tradicional de Módulo 11.


3. Implementação em JavaScript / TypeScript (Compatível com os dois formatos)

A função abaixo valida perfeitamente tanto o CNPJ clássico (100% numérico) quanto o novo CNPJ alfanumérico:

/**
 * Valida CNPJ clássico e o novo padrão alfanumérico da Receita Federal
 */
function validarCNPJ(cnpj) {
  if (!cnpj || typeof cnpj !== 'string') return false;

  // Remove pontuação e espaços, convertendo para maiúsculo
  const limpo = cnpj.replace(/[^A-Za-z0-9]/g, '').toUpperCase();

  if (limpo.length !== 14) return false;

  // Rejeita sequências repetidas óbvias de números
  if (/^(\d)\1{13}$/.test(limpo)) return false;

  // Os 2 últimos dígitos DEVEM ser estritamente numéricos
  if (!/^\d{2}$/.test(limpo.slice(12))) return false;

  const pesos1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
  const pesos2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];

  // Cálculo do 1º Dígito Verificador
  let soma1 = 0;
  for (let i = 0; i < 12; i++) {
    const valorAscii = limpo.charCodeAt(i) - 48;
    soma1 += valorAscii * pesos1[i];
  }
  const resto1 = soma1 % 11;
  const dv1 = resto1 < 2 ? 0 : 11 - resto1;

  if (parseInt(limpo[12], 10) !== dv1) return false;

  // Cálculo do 2º Dígito Verificador
  let soma2 = 0;
  for (let i = 0; i < 12; i++) {
    const valorAscii = limpo.charCodeAt(i) - 48;
    soma2 += valorAscii * pesos2[i];
  }
  soma2 += dv1 * pesos2[12]; // Adiciona o 1º DV no cálculo do 2º DV

  const resto2 = soma2 % 11;
  const dv2 = resto2 < 2 ? 0 : 11 - resto2;

  return parseInt(limpo[13], 10) === dv2;
}

4. Implementação em Python

def validar_cnpj(cnpj: str) -> bool:
    import re
    
    limpo = re.sub(r'[^A-Za-z0-9]', '', cnpj).upper()
    
    if len(limpo) != 14:
        return False
        
    if limpo == limpo[0] * 14 and limpo.isdigit():
        return False
        
    if not limpo[12:].isdigit():
        return False
        
    pesos1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
    pesos2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
    
    # 1º DV
    soma1 = sum((ord(char) - 48) * peso for char, peso in zip(limpo[:12], pesos1))
    resto1 = soma1 % 11
    dv1 = 0 if resto1 < 2 else 11 - resto1
    
    if int(limpo[12]) != dv1:
        return False
        
    # 2º DV
    soma2 = sum((ord(char) - 48) * peso for char, peso in zip(limpo[:12], pesos2[:12]))
    soma2 += dv1 * pesos2[12]
    resto2 = soma2 % 11
    dv2 = 0 if resto2 < 2 else 11 - resto2
    
    return int(limpo[13]) == dv2

5. Cuidados no Banco de Dados

Se você ainda tem tabelas legadas armazenando CNPJ em campos numéricos (BIGINT), a migração para VARCHAR(14) (ou VARCHAR(18) com pontuação) é urgente:

  • ALTER TABLE empresas MODIFY COLUMN cnpj VARCHAR(14) NOT NULL;
  • Atualize também as máscaras de input nos formulários web/mobile para aceitarem letras maiúsculas nas primeiras 12 posições.

O sistema ou ERP de vocês já está preparado para receber CNPJ alfanumérico ou a migração ainda está no backlog?


Gerador e Validador em lote com suporte ao novo CNPJ Alfanumérico: tecmestre.com.br/gerador-validador-cpf-cnpj/

Carregando publicação patrocinada...
1

A regex de repetidos só casa 14 dígitos iguais. AAAAAAAAAAAA00 atravessa essa checagem e vai para o módulo 11, com A valendo 17 (charCode menos 48). Doze letras iguais não são o mesmo caso que 00000000000000.