CS Coder
Delphi

CNPJ alfanumérico no Delphi: valide o novo e o antigo formato com CSCoder.Validacoes

Implemente ValidarNovoCNPJ com módulo 11, conversão ASCII, máscara rigorosa e compatibilidade com CNPJs numéricos. Inclui unit completa e testes.

· 10 min de leitura
Objetivo e formato

Validar estrutura e dígitos verificadores dos dois formatos sem transformar o identificador em número

Tutorial · prática orientada · Intermediário
Antes de experimentar

Units, strings, funções e leitura de laços

Unit compilada e testada com DCC32 37.0, build 37.0.59082.6021. Referência: Delphi 11.3 e 13.2, não verificados individualmente.

Documentação, instalação e limites de CSCoder.Validacoes

Experimentar o contrato no navegador

Um cadastro começa a recusar um cliente porque o CNPJ contém letras. A correção parece simples: liberar o teclado e alterar a máscara. Mas o problema também pode estar no banco, em uma expressão regular, em um DTO ou numa rotina que chama StrToInt64.

Vamos implementar ValidarNovoCNPJ. Ela aceita os CNPJs alfanuméricos e também os numéricos compatíveis. A mesma unit oferece ValidarAntigoCNPJ, que exige apenas números na identificação. Use a primeira em cadastros que precisam conviver com os dois padrões; reserve a segunda para contratos explicitamente numéricos. A unit não depende de formulário, rede ou banco de dados: pode ser utilizada por VCL, FireMonkey, UniGUI e serviços.

O que mudou no CNPJ

O novo formato mantém 14 posições: as primeiras 12 aceitam números e letras maiúsculas de A a Z; as duas últimas continuam numéricas. CNPJs existentes permanecem válidos. A coexistência exige que a aplicação aceite os dois formatos. Perguntas e respostas da Receita Federal.

O assunto já chegou aos cadastros: a Receita informou a emissão do primeiro CNPJ alfanumérico em 31 de julho de 2026, com o número 00.000.000/E08G-12. Ele será um dos vetores de teste deste artigo. Comunicado oficial.

Validade matemática não comprova cadastro

O contrato das funções é pequeno: verificar formato e dígitos verificadores. True não significa que a empresa existe, está ativa ou pertence a quem informou o número. Quando o negócio exigir comprovação cadastral, trate a consulta como uma etapa separada, com seus próprios erros e critérios.

Também não transforme CNPJ em inteiro. O identificador precisa preservar zeros à esquerda e agora pode conter letras. No seu contrato de aplicação, use string; no JSON, uma string; no armazenamento, uma coluna textual adequada. Essa decisão evita que uma conversão incidental modifique a identidade que o usuário informou.

O detalhe que muda a conta

O módulo 11 continua em uso. A diferença é converter cada caractere com seu código ASCII menos 48: 0 vale 0, 9 vale 9, A vale 17 e Z vale 42. Não é uma conversão em base 36, em que A teria outro valor.

Os pesos percorrem a base da direita para a esquerda, de 2 a 9, reiniciando em 2. O primeiro DV usa as 12 posições; o segundo inclui o primeiro DV calculado. Resto 0 ou 1 produz DV 0; nos demais casos, o DV é 11 menos o resto. O exemplo oficial 12.ABC.345/01DE-35 resulta em somas 459 e 424, produzindo os dígitos 3 e 5. Manual técnico da Receita/Serpro.

No Delphi, Ord retorna o valor do caractere. Antes de usá-lo na conta, nossa rotina limita o alfabeto aos caracteres ASCII permitidos. Um caractere Unicode visualmente parecido com A ou 5 não deve entrar silenciosamente no cálculo.

Defina o que a entrada pode conter

Esta implementação aceita o valor sem pontuação, com 14 posições, ou a máscara completa XX.XXX.XXX/XXXX-DD, com 18. A posição de cada separador é conferida. Espaços externos são removidos por Trim; letras minúsculas ASCII são convertidas para maiúsculas como conveniência de digitação. O identificador normalizado segue o alfabeto oficial.

Espaços internos, acentos, símbolos extras, máscara quebrada e letras nos DVs são rejeitados. Isso é uma escolha explícita do nosso contrato de entrada, não uma autorização para modificar identificadores arbitrários. Uma rotina que “remove tudo que não é número” destruiria exatamente as letras que precisamos preservar.

O valor inteiramente zerado merece uma rejeição adicional: a operação matemática produziria 00, mas essa sequência não deve ser aceita como identificação. Já zeros na raiz não são motivo de rejeição — o exemplo real da Receita começa com eles.

Unit CSCoder.Validacoes: duas funções booleanas

Salve como CSCoder.Validacoes.pas e adicione a unit ao projeto. Os helpers ficam na implementação; a interface pública expõe duas funções booleanas.

delphi
{
  CSCoder.Validacoes
  Claudio Santos | CS Coder | https://cscoder.com.br/
  SPDX-License-Identifier: MIT

  Uso, modificacao e redistribuicao permitidos, inclusive em projetos
  comerciais. Preserve o aviso de autoria e o texto da licenca.
  Fornecido sem garantias, conforme a licenca abaixo.

  MIT License
  
  Copyright (c) 2026 Claudio Santos (CS Coder)
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:
  
  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
}

unit CSCoder.Validacoes;

interface

function ValidarNovoCNPJ(const Valor: string): Boolean;
function ValidarAntigoCNPJ(const Valor: string): Boolean;

implementation

uses System.SysUtils;

function Normalizar(const Valor: string; out CNPJ: string): Boolean;
var
  S: string;
  I: Integer;
  C: Char;
begin
  Result := False;
  CNPJ := '';
  S := Trim(Valor);
  case Length(S) of
    14: CNPJ := S;
    18:
      begin
        if (S[3] <> '.') or (S[7] <> '.') or
           (S[11] <> '/') or (S[16] <> '-') then
          Exit;
        CNPJ := Copy(S, 1, 2) + Copy(S, 4, 3) +
                Copy(S, 8, 3) + Copy(S, 12, 4) + Copy(S, 17, 2);
      end;
  else
    Exit;
  end;

  for I := 1 to 12 do
  begin
    C := CNPJ[I];
    // Apenas letras ASCII: nao converte caracteres Unicode parecidos.
    if (C >= 'a') and (C <= 'z') then
      C := Char(Ord(C) - Ord('a') + Ord('A'));
    if not (((C >= '0') and (C <= '9')) or
            ((C >= 'A') and (C <= 'Z'))) then
      Exit;
    CNPJ[I] := C;
  end;
  for I := 13 to 14 do
    if (CNPJ[I] < '0') or (CNPJ[I] > '9') then
      Exit;
  // Todos os zeros passam na conta, mas nao identificam um CNPJ.
  if CNPJ = '00000000000000' then
    Exit;
  Result := True;
end;

function CalcularDV(const Base: string): Integer;
var
  I, Peso, Soma, Resto: Integer;
begin
  Soma := 0;
  Peso := 2;
  for I := Length(Base) downto 1 do
  begin
    Soma := Soma + (Ord(Base[I]) - Ord('0')) * Peso;
    Inc(Peso);
    if Peso > 9 then
      Peso := 2;
  end;
  Resto := Soma mod 11;
  if Resto < 2 then
    Result := 0
  else
    Result := 11 - Resto;
end;

function ValidarNovoCNPJ(const Valor: string): Boolean;
var
  S, Base: string;
  DV1, DV2: Integer;
begin
  Result := False;
  if not Normalizar(Valor, S) then
    Exit;
  Base := Copy(S, 1, 12);
  DV1 := CalcularDV(Base);
  if Ord(S[13]) - Ord('0') <> DV1 then
    Exit;
  DV2 := CalcularDV(Base + Char(Ord('0') + DV1));
  Result := Ord(S[14]) - Ord('0') = DV2;
end;

function ValidarAntigoCNPJ(const Valor: string): Boolean;
var
  S: string;
  I: Integer;
begin
  Result := False;
  if not Normalizar(Valor, S) then
    Exit;
  for I := 1 to 12 do
    if (S[I] < '0') or (S[I] > '9') then
      Exit;
  Result := ValidarNovoCNPJ(S);
end;

end.

O normalizador verifica o tamanho antes de acessar as posições. O cálculo percorre no máximo 13 caracteres, com valores e pesos pequenos; Integer comporta a soma com folga. O segundo DV utiliza o primeiro que foi calculado, e não uma letra ou número arbitrário extraído de uma entrada sem validação.

Como chamar sem amarrar a regra à tela

delphi
uses CSCoder.Validacoes;

// A tela decide como apresentar a mensagem.
if not ValidarNovoCNPJ('12.ABC.345/01DE-35') then
  raise EArgumentException.Create('Confira o CNPJ informado.');

O trecho acima pressupõe System.SysUtils para a exceção. Em um endpoint, você pode devolver um erro de entrada; no mobile, destacar o campo; em uma rotina de importação, registrar a linha recusada. A função não precisa conhecer nenhuma dessas apresentações.

Para persistir, mantenha uma política única de normalização e aplique-a de forma consistente na tela, API e importação. Não salve ora com máscara, ora sem máscara, esperando que um índice de unicidade descubra que os valores representam o mesmo identificador.

Casos que precisam entrar no teste

Entrada Resultado esperado Motivo
12.ABC.345/01DE-35 True Exemplo do manual
00.000.000/E08G-12 True Exemplo divulgado pela Receita
12.345.678/0001-95 True Compatibilidade numérica; exemplo matemático
12abc34501de35 True Política de normalização ASCII
12ABC34501DE34 False Segundo DV alterado
12ABC34501DEA5 False Letra no primeiro DV
12.ABC.345-01DE/35 False Separadores fora de posição
00000000000000 False Sequência zerada

O projeto para download contém 370 verificações. Além das entradas de borda, há 80 bases sintéticas, com DVs obtidos por uma referência de pesos explícitos, e 80 versões com o segundo DV alterado. Esses dados exercitam o algoritmo; não representam empresas inscritas. A unit e o runner foram compilados com DCC32 37.0, build 37.0.59082.6021, com verificações de faixa e overflow ativadas. As versões 11.3 e 13.2 não foram executadas individualmente.

A função é só uma parte da adaptação

Procure no projeto por conversões numéricas de CNPJ, validações baseadas exclusivamente em dígitos, máscaras, tipos dos campos persistentes e regras de importação. Confira também se a tela mobile permite digitar letras. Depois percorra um cadastro completo: entrada, validação, envio, armazenamento e leitura de volta.

Faça isso com um exemplo numérico e um alfanumérico, preservando zeros à esquerda. Integrações fiscais e serviços externos devem ser avaliados conforme seus contratos e documentação próprios; passar em ValidarNovoCNPJ não comprova que um arquivo fiscal ou uma requisição será aceito.

Como exercício, escreva testes que recusem pontuação duplicada e dígitos de largura completa, mantendo os exemplos válidos. Em seguida, leia Tela, serviço e domínio para decidir onde colocar essa regra no seu cadastro.

Licença: código livre com crédito preservado

A unit e o projeto de testes são disponibilizados sob a licença MIT, com crédito a Claudio Santos (CS Coder). Você pode utilizar, modificar e redistribuir o código, inclusive em aplicações comerciais e de código fechado, preservando o aviso de autoria e o texto da licença nas cópias ou partes substanciais do código. O cabeçalho do .pas contém a licença completa; o ZIP inclui LICENSE.txt.

O código é fornecido sem garantias, conforme o texto da licença. Essa permissão se aplica ao pacote de código, não é uma licença geral para as imagens, a marca ou os demais artigos. Texto da licença MIT.

Downloads: inclua a unit no seu projeto

Baixar CSCoder.Validacoes.pas

O arquivo é a mesma unit exibida neste artigo, pronta para adicionar ao projeto. Inclua CSCoder.Validacoes no uses e chame uma das funções. A compilação e os 370 resultados do runner foram verificados antes de disponibilizar o arquivo. Não há dependências de terceiros; a implementação utiliza System.SysUtils.

O pacote abaixo inclui também o projeto console de testes. Para outros exemplos e recursos, consulte a página de downloads.

Inspecione a conta e o contrato

Manual de DV da Receita conferido em 08/10/2026; vetor técnico 12ABC34501DE35.

  1. No laboratório CNPJ, confira normalização ASCII.
  2. Observe valores: código ASCII menos 48; A contribui com 17.
  3. Compare pesos, soma e resto módulo 11 do primeiro DV. Acrescente-o e repita para o segundo.
  4. Altere o DV e confirme recusa; compare 11222333000181 e todos os zeros.

Checklist: campo textual, máscaras, integrações, importação/exportação e ordenação; não converter documento em número. Mudanças de banco ficam adiadas. Formato e DV não comprovam existência ou situação cadastral.

Abrir projeto de exemplo ↗