Ferramentas gratuitas para desenvolvedores. Nenhum dado real de pessoas é consultado ou armazenado.Como funciona o algoritmo do CPF →
Delphi

Validar, gerar e formatar CNPJ em Delphi

Unit em Delphi para validar, gerar e formatar CNPJ numérico e alfanumérico com Ord(c) - 48, testes com DUnitX e consulta à API com TNetHTTPClient.

Roberto GuerraPublicado em 05 de outubro de 2026Editar no GitHub

Delphi ainda move muito ERP, sistema fiscal e automação comercial no Brasil, e é justamente nesses sistemas que o CNPJ alfanumérico dá mais trabalho: campos Integer ou Int64, máscaras 99.999.999/9999-99 em TMaskEdit e funções de validação que fazem StrToInt em cada caractere. A unit abaixo troca essa conversão por Ord(c) - 48, que dá 0 a 9 para dígitos e 17 a 42 para letras de A a Z, e assim valida os dois formatos com o mesmo cálculo. Ela usa só a System.SysUtils e foi escrita para Delphi 10.4 ou mais recente. O guia CNPJ alfanumérico: o que muda no seu sistema lista os outros pontos a revisar.

Validar CNPJ em Delphi (numérico e alfanumérico)

CnpjUtils.pas
unit CnpjUtils;

interface

function ValidarCNPJ(const S: string): Boolean;
function GerarCNPJ(Alfanumerico: Boolean = False; Formatado: Boolean = False): string;
function LimparCNPJ(const S: string): string;
function FormatarCNPJ(const S: string): string;

implementation

uses
System.SysUtils;

const
Pesos1: array[0..11] of Integer = (5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2);
Pesos2: array[0..12] of Integer = (6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2);

function CalcularDigito(const Base: string; const Pesos: array of Integer): Integer;
var
I, Soma, Resto: Integer;
begin
Soma := 0;
for I := 1 to Length(Base) do
  Soma := Soma + (Ord(Base[I]) - 48) * Pesos[I - 1];
Resto := Soma mod 11;
if Resto < 2 then
  Result := 0
else
  Result := 11 - Resto;
end;

function ValidarCNPJ(const S: string): Boolean;
var
C: Char;
Cnpj, Base: string;
Dv1, Dv2: Integer;
begin
Result := False;
Cnpj := '';
for C in UpperCase(S) do
  if CharInSet(C, ['0'..'9', 'A'..'Z']) then
    Cnpj := Cnpj + C
  else if not CharInSet(C, ['.', '/', '-', ' ']) then
    Exit;
if Length(Cnpj) <> 14 then
  Exit;
if not (CharInSet(Cnpj[13], ['0'..'9']) and CharInSet(Cnpj[14], ['0'..'9'])) then
  Exit;
Base := Copy(Cnpj, 1, 12);
if Base = StringOfChar(Base[1], 12) then
  Exit;
Dv1 := CalcularDigito(Base, Pesos1);
Dv2 := CalcularDigito(Base + IntToStr(Dv1), Pesos2);
Result := (Ord(Cnpj[13]) - 48 = Dv1) and (Ord(Cnpj[14]) - 48 = Dv2);
end;

O que observar:

  • UpperCase da SysUtils converte só de a até z. É o que se quer aqui: 12.abc.345/01de-35 vira 12.ABC.345/01DE-35, e letras acentuadas continuam fora do conjunto aceito.
  • CharInSet é a forma recomendada de testar Char contra um conjunto desde que string passou a ser Unicode; C in [...] gera aviso do compilador.
  • Só pontos, barra, hífen e espaços são ignorados. Qualquer outro símbolo faz a função sair com False.
  • Strings começam no índice 1, por isso o laço vai de 1 a Length(Base) e o peso é lido em Pesos[I - 1], já que o array aberto começa em 0.
  • StringOfChar(Base[1], 12) recusa bases repetidas como 00.000.000/0000-00, que fecham a conta, mas não são válidas.

Com 11.222.333/0001-81, a primeira soma é 102, o resto é 3 e o dígito é 8; a segunda soma é 120, o resto é 10 e o dígito é 1. Com 12.ABC.345/01DE-35, as somas são 459 e 424, os restos 8 e 6, e os dígitos 3 e 5.

Gerar CNPJ válido em Delphi

CnpjUtils.pas
function GerarCNPJ(Alfanumerico: Boolean = False; Formatado: Boolean = False): string;
const
Alfabeto = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var
Base: string;
I, Tamanho, Dv1, Dv2: Integer;
begin
if Alfanumerico then
  Tamanho := 36
else
  Tamanho := 10;
repeat
  Base := '';
  for I := 1 to 12 do
    Base := Base + Alfabeto[Random(Tamanho) + 1];
until Base <> StringOfChar(Base[1], 12);
Dv1 := CalcularDigito(Base, Pesos1);
Dv2 := CalcularDigito(Base + IntToStr(Dv1), Pesos2);
Result := Base + IntToStr(Dv1) + IntToStr(Dv2);
if Formatado then
  Result := FormatarCNPJ(Result);
end;

Random não é criptográfico, o que basta para dados de teste; chame Randomize uma vez na inicialização (o fim da unit, mais abaixo, já faz isso). O CNPJ gerado passa na validação, mas pode coincidir com um CNPJ real por acaso, então use-o só em bases de homologação. Para gerar filiais de uma mesma raiz, veja o guia da estrutura do CNPJ.

Formatar e limpar CNPJ em Delphi

CnpjUtils.pas
function LimparCNPJ(const S: string): string;
var
C: Char;
begin
Result := '';
for C in UpperCase(S) do
  if CharInSet(C, ['0'..'9', 'A'..'Z']) then
    Result := Result + C;
end;

function FormatarCNPJ(const S: string): string;
var
C: string;
begin
C := LimparCNPJ(S);
if Length(C) <> 14 then
  raise EArgumentException.Create('CNPJ precisa de 14 caracteres');
Result := Copy(C, 1, 2) + '.' + Copy(C, 3, 3) + '.' + Copy(C, 6, 3) + '/' +
  Copy(C, 9, 4) + '-' + Copy(C, 13, 2);
end;

initialization
Randomize;

end.

FormatarCNPJ('12abc34501de35') devolve '12.ABC.345/01DE-35', e aplicar a função de novo no resultado não muda nada. No banco, troque campos numéricos por CHAR(14) ou VARCHAR(14) e grave a versão limpa. No TMaskEdit, a máscara 99.999.999/9999-99;0;_ não aceita letras; use AA.AAA.AAA/AAAA-99;0;_ (em que A aceita letra ou dígito) e chame UpperCase no OnExit, ou trate a digitação em um TEdit comum com FormatarCNPJ.

Testes

Com DUnitX, cada atributo TestCase vira um teste separado. Os parâmetros chegam como texto separado por vírgula e são convertidos para os tipos do método.

CnpjUtilsTests.pas
unit CnpjUtilsTests;

interface

uses
DUnitX.TestFramework;

type
[TestFixture]
TCnpjTests = class
public
  [Test]
  [TestCase('NumericoValido', '11.222.333/0001-81,True')]
  [TestCase('AlfanumericoValido', '12.ABC.345/01DE-35,True')]
  [TestCase('DigitoErrado', '11.222.333/0001-82,False')]
  [TestCase('Repetido', '00.000.000/0000-00,False')]
  procedure Validar(const Cnpj: string; Esperado: Boolean);
  [Test]
  procedure GeradosSaoValidos;
  [Test]
  procedure FormatarEhIdempotente;
end;

implementation

uses
CnpjUtils;

procedure TCnpjTests.Validar(const Cnpj: string; Esperado: Boolean);
begin
Assert.IsTrue(ValidarCNPJ(Cnpj) = Esperado, Cnpj);
end;

procedure TCnpjTests.GeradosSaoValidos;
var
I: Integer;
begin
for I := 1 to 1000 do
begin
  Assert.IsTrue(ValidarCNPJ(GerarCNPJ(False)));
  Assert.IsTrue(ValidarCNPJ(GerarCNPJ(True)));
end;
end;

procedure TCnpjTests.FormatarEhIdempotente;
begin
Assert.AreEqual('12.ABC.345/01DE-35', FormatarCNPJ(FormatarCNPJ('12abc34501de35')));
end;

initialization
TDUnitX.RegisterTestFixture(TCnpjTests);

end.

Se o projeto não usa DUnitX, os mesmos quatro casos cabem em um programa de console com Writeln(ValidarCNPJ('12.ABC.345/01DE-35')). Outros números estão nos exemplos de CNPJ alfanumérico para teste.

Usar a API em vez de reimplementar

A API do cpf.dev.br valida e gera CNPJs por HTTP, sem chave, com limite de 60 requisições por minuto por IP. Envie o CNPJ sem máscara, ou com a barra codificada como %2F. TNetHTTPClient e System.JSON já vêm com o Delphi. O trecho abaixo é só o corpo do procedimento que faz a chamada e lê a resposta; não é um programa completo — falta o uses do seu projeto e tratamento de erro de rede/timeout.

ConsultaCnpj.pas
uses
System.SysUtils, System.JSON, System.Net.HttpClientComponent, CnpjUtils;

procedure ConsultarCNPJ(const Cnpj: string);
var
Http: TNetHTTPClient;
Json: TJSONValue;
Formatado: string;
begin
Http := TNetHTTPClient.Create(nil);
try
  Json := TJSONObject.ParseJSONValue(Http.Get(
    'https://www.cpf.dev.br/api/v1/cnpj/validar/' + LimparCNPJ(Cnpj)).ContentAsString(TEncoding.UTF8));
  try
    // {"valido":true,"cnpj":"12ABC34501DE35","formatado":"12.ABC.345/01DE-35",
    //  "formato":"alfanumerico","raiz":"12ABC345","ordem":"01DE","matriz":false}
    if Json.TryGetValue<string>('formatado', Formatado) then
      Writeln(Json.GetValue<Boolean>('valido'), ' ', Formatado)
    else
      Writeln('Resposta sem o campo "formatado" (ex.: CNPJ ausente na URL).');
  finally
    Json.Free;
  end;
finally
  Http.Free;
end;
end;

Para gerar uma lista, chame https://www.cpf.dev.br/api/v1/cnpj/gerar?quantidade=5&formato=alfanumerico&formatado=true e leia o array cnpjs. Na validação de telas, a função local continua sendo a melhor opção, porque não depende de rede. Para conferir um número à mão, use o validador de CNPJ.

Leia também