Regex de CNPJ numérico e alfanumérico
Expressões regulares para CNPJ numérico e alfanumérico, com e sem máscara, CPF ou CNPJ, Google Forms, HTML pattern e máscara de input que aceita letras.
Toda regex de CNPJ escrita antes de 2026 tem uma premissa que deixou de valer: a de que o número só contém dígitos. Com o CNPJ alfanumérico, as 12 primeiras posições aceitam letras de A a Z, e uma expressão com \d{14} passa a recusar números válidos. Este guia reúne as expressões para os dois formatos, com e sem máscara, e mostra as adaptações para Google Forms, planilhas e o atributo pattern do HTML.
Numérico com e sem máscara
Para sistemas que, por algum motivo, ainda só lidam com o formato numérico:
const CNPJ_NUMERICO = /^\d{14}$/;
const CNPJ_NUMERICO_MASCARA = /^\d{2}\.\d{3}\.\d{3}\/\d{4}-\d{2}$/;
const CNPJ_NUMERICO_FLEXIVEL = /^\d{2}\.?\d{3}\.?\d{3}\/?\d{4}-?\d{2}$/;
CNPJ_NUMERICO_MASCARA.test('11.222.333/0001-81'); // true
CNPJ_NUMERICO.test('11222333000181'); // true
CNPJ_NUMERICO.test('12ABC34501DE35'); // false
A barra precisa de escape (\/) dentro de um literal de regex em JavaScript, porque a barra delimita a expressão. Em strings passadas para new RegExp, em Python e no HTML, ela pode ficar sem escape. O ponto, por outro lado, precisa de escape em qualquer lugar: sozinho, ele significa “qualquer caractere”.
Em Python 3, \d aceita dígitos de outros sistemas de escrita, como os arábico-índicos. Se a entrada vem de fora, prefira [0-9] ou a flag re.ASCII.
Alfanumérico com e sem máscara
A troca é pontual: nas 12 primeiras posições, \d vira [A-Z0-9]. Os dois últimos caracteres continuam \d, porque os dígitos verificadores são sempre numéricos. Estas são as expressões da biblioteca de referência do site:
const CNPJ_ALFANUMERICO = /^[A-Z0-9]{12}\d{2}$/;
const CNPJ_ALFANUMERICO_MASCARA = /^[A-Z0-9]{2}\.[A-Z0-9]{3}\.[A-Z0-9]{3}\/[A-Z0-9]{4}-\d{2}$/;
const CNPJ_ALFANUMERICO_FLEXIVEL = /^[A-Z0-9]{2}\.?[A-Z0-9]{3}\.?[A-Z0-9]{3}\/?[A-Z0-9]{4}-?\d{2}$/;
CNPJ_ALFANUMERICO_MASCARA.test('12.ABC.345/01DE-35'); // true
CNPJ_ALFANUMERICO_MASCARA.test('11.222.333/0001-81'); // true: numérico também passa
CNPJ_ALFANUMERICO.test('12ABC34501DE35'); // true
CNPJ_ALFANUMERICO.test('12ABC34501DE3X'); // false: letra no dígito
CNPJ_ALFANUMERICO.test('12abc34501de35'); // false: minúsculasComo [A-Z0-9] inclui os dígitos, a expressão alfanumérica aceita também todos os CNPJs numéricos. Não é preciso manter as duas: substitua a antiga pela nova.
As expressões aceitam só maiúsculas, e isso é proposital. O formato usa letras maiúsculas, e a recomendação é converter a entrada antes de testar, com valor.toUpperCase(), em vez de usar a flag i. Assim o valor que passa no teste é o mesmo que vai para o banco. Em Python, o equivalente é re.fullmatch(r'[A-Z0-9]{12}[0-9]{2}', valor.upper()).
Cada linguagem tem um detalhe nas âncoras. Em JavaScript, sem a flag m, $ só casa no fim do texto. Em Python e PHP, $ também casa antes de uma quebra de linha final, então "12ABC34501DE35\n" passaria no teste; use re.fullmatch em Python e \z (ou o modificador D) em PHP. Em Java, String.matches já exige que a expressão case com o texto inteiro, e as âncoras são dispensáveis. Em C#, Regex.IsMatch procura em qualquer ponto, então mantenha ^ e $ e prefira \z no fim. Esses detalhes importam quando o valor vem de um arquivo ou formulário que pode trazer espaços e quebras de linha: o mais seguro é remover espaços das pontas antes do teste.
CPF ou CNPJ em uma regex
Para um campo “CPF ou CNPJ”, junte as duas expressões com alternância:
const CPF_OU_CNPJ = /^(?:\d{3}\.?\d{3}\.?\d{3}-?\d{2}|[A-Z0-9]{2}\.?[A-Z0-9]{3}\.?[A-Z0-9]{3}\/?[A-Z0-9]{4}-?\d{2})$/;
function tipoDocumento(valor) {
const v = String(valor).toUpperCase();
if (!CPF_OU_CNPJ.test(v)) return null;
return v.replace(/[^A-Z0-9]/g, '').length === 11 ? 'cpf' : 'cnpj';
}
tipoDocumento('529.982.247-25'); // 'cpf'
tipoDocumento('12.abc.345/01de-35'); // 'cnpj'
tipoDocumento('529.982.247-2'); // nullO grupo (?:...) garante que as âncoras se apliquem às duas alternativas. O CPF continua só numérico, então a primeira alternativa mantém \d. A distinção pelo tamanho é segura porque, depois de limpos, o CPF tem 11 caracteres e o CNPJ, 14. Repare que a limpeza usa [^A-Z0-9], e não \D: com \D, as letras do CNPJ seriam descartadas e o tamanho sairia errado. O guia de regex de CPF traz as expressões só de CPF.
Google Forms, planilhas e HTML pattern
Google Forms. Em Validação da resposta, escolha Expressão regular e Corresponde a. O Forms usa uma sintaxe no estilo RE2, sem lookahead, lookbehind nem retrovisores. Como o usuário pode digitar em minúsculas, aceite as duas caixas:
^[A-Za-z0-9]{2}\.?[A-Za-z0-9]{3}\.?[A-Za-z0-9]{3}/?[A-Za-z0-9]{4}-?[0-9]{2}$
Escreva na mensagem de erro o formato esperado, por exemplo “Use o formato 12.ABC.345/01DE-35 ou 11.222.333/0001-81”.
Google Planilhas. REGEXMATCH usa o mesmo dialeto. Com a planilha em português, separe os argumentos com ponto e vírgula e converta para maiúsculas antes:
=REGEXMATCH(UPPER(TO_TEXT(A2)); "^[A-Z0-9]{2}\.?[A-Z0-9]{3}\.?[A-Z0-9]{3}/?[A-Z0-9]{4}-?[0-9]{2}$")
Formate a coluna como texto antes de colar os dados. Uma coluna numérica descarta zeros à esquerda e não comporta letras.
HTML pattern. O navegador ancora o padrão no início e no fim, e não há barras delimitadoras:
<label for="cnpj">CNPJ</label>
<input id="cnpj" name="cnpj" autocapitalize="characters" maxlength="18"
pattern="[A-Za-z0-9]{2}\.?[A-Za-z0-9]{3}\.?[A-Za-z0-9]{3}/?[A-Za-z0-9]{4}-?[0-9]{2}"
title="14 caracteres, com ou sem pontuação">
Os navegadores atuais compilam o pattern com a flag v, que é estrita com escapes: \. funciona, mas \- fora de colchetes faz o navegador ignorar o atributo. Por isso o hífen e a barra ficam sem escape. Não use inputmode="numeric": no celular, ele abre um teclado sem letras.
Máscara de input que aceita letras
As máscaras clássicas de CNPJ começam com replace(/\D/g, ''), que apaga as letras. A versão abaixo converte para maiúsculas, mantém letras e dígitos e insere a pontuação conforme o usuário digita:
function mascaraCnpj(valor) {
const c = String(valor).toUpperCase().replace(/[^A-Z0-9]/g, '').slice(0, 14);
return c.replace(
/^([A-Z0-9]{2})([A-Z0-9]{1,3})?([A-Z0-9]{1,3})?([A-Z0-9]{1,4})?([A-Z0-9]{1,2})?$/,
(_, a, b, d, e, f) => a + (b ? '.' + b : '') + (d ? '.' + d : '') + (e ? '/' + e : '') + (f ? '-' + f : ''),
);
}
mascaraCnpj('12abc3'); // '12.ABC.3'
mascaraCnpj('12abc34501d'); // '12.ABC.345/01D'
mascaraCnpj('12.abc.345/01de-35'); // '12.ABC.345/01DE-35'Os grupos são gulosos, então cada um se completa antes de o próximo começar, e os opcionais só geram separador quando têm conteúdo. A máscara não impede uma letra nas duas últimas posições; essa checagem é da validação. Para cursor e colagem em React, Vue e Angular, veja o guia de máscara de CPF, cuja técnica é a mesma, e o formatador de CNPJ para o comportamento esperado.
Regex não substitui o dígito verificador
As expressões alfanuméricas com máscara ou flexíveis aceitam 12.ABC.345/01DE-36, que tem o formato certo e o segundo dígito errado. Regex lê caracteres; o dígito verificador exige uma soma ponderada e uma divisão por 11, com o valor de cada caractere dado pelo código ASCII menos 48. O fluxo completo é: conferir o formato, normalizar para 14 caracteres em maiúsculas e calcular os verificadores.
Em motores com lookahead e retrovisores (JavaScript, Python, Java, PHP), dá para recusar sequências repetidas na própria regex:
const SEM_REPETIDOS = /^(?!([A-Z0-9])\1{11})[A-Z0-9]{12}\d{2}$/;
Isso não funciona no Google Forms nem em outros ambientes RE2, e mesmo onde funciona, a checagem dos dígitos continua obrigatória. A função completa está em CNPJ em JavaScript e nas demais linguagens; o passo a passo do cálculo, no guia sobre a estrutura do CNPJ; e o validador de CNPJ confere qualquer número na hora.
Perguntas frequentes
Qual regex aceita o CNPJ alfanumérico com e sem pontuação?
Use ^[A-Z0-9]{2}\.?[A-Z0-9]{3}\.?[A-Z0-9]{3}\/?[A-Z0-9]{4}-?\d{2}$. As 12 primeiras posições aceitam letras e dígitos, os separadores são opcionais e os dois últimos caracteres são sempre dígitos.
A regex antiga de CNPJ ainda funciona?
Só para CNPJs numéricos. Expressões com \d nas 12 primeiras posições recusam números como 12.ABC.345/01DE-35, atribuídos a novas inscrições desde julho de 2026. Troque \d por [A-Z0-9] nessas posições.
Dá para validar o dígito verificador do CNPJ com regex?
Não. O dígito depende de uma soma ponderada e de uma divisão por 11, operações que regex não faz. Use regex para o formato e uma função para os dígitos.