O algoritmo, independente de linguagem
Antes de escolher a implementação, vale fixar o pseudocódigo — todas as versões abaixo são tradução literal dele:
função digito(sequencia):
soma ← 0
para i de 0 até tamanho(sequencia) - 1:
valor ← ascii(sequencia[i]) - 48
peso ← ((tamanho(sequencia) - 1 - i) mod 8) + 2
soma ← soma + valor * peso
resto ← soma mod 11
se resto < 2 então devolva 0 senão devolva 11 - resto
função validar(entrada):
cnpj ← maiúsculas(entrada) sem caracteres fora de [0-9A-Z]
se tamanho(cnpj) ≠ 14 devolva falso
se cnpj[13..14] não forem dígitos devolva falso
base ← cnpj[1..12]
d1 ← digito(base)
d2 ← digito(base + d1)
devolva cnpj[13..14] = d1 + d2
Ordem sugerida de migração
- Banco de dados primeiro. Sem a coluna em texto, nenhuma correção de código adianta. Veja como migrar.
- Camada de domínio. Substitua a validação antiga pela função desta página e cubra com testes.
- Bordas do sistema. Formulários, importadores de arquivo, APIs, relatórios e integrações — é onde ficam as regex e máscaras esquecidas.
- Homologação com massa alfanumérica. Use o gerador para popular o ambiente antes de o primeiro cliente aparecer com um CNPJ com letras.