cnpjcpf.
Código · Go

Validar CNPJ em Go

Uma função sem dependências que valida CNPJ pelo módulo 11numérico e alfanumérico no mesmo código. A conversão ASCII − 48 trata letra e dígito de forma uniforme; só os 2 verificadores continuam numéricos.

A função

Go
package brdoc

import (
	"regexp"
	"strings"
)

var (
	reSep  = regexp.MustCompile(`[./-]`)
	reCNPJ = regexp.MustCompile(`^[A-Z0-9]{12}\d{2}$`)
)

// RE2 não tem backreference, então repetidos vão por função, não por regex.
func allSame(s string) bool {
	for i := 1; i < len(s); i++ {
		if s[i] != s[0] {
			return false
		}
	}
	return len(s) > 0
}

func dv(base string, w []int) int {
	s := 0
	for i, p := range w {
		s += (int(base[i]) - 48) * p
	}
	if r := s % 11; r >= 2 {
		return 11 - r
	}
	return 0
}

func IsValidCNPJ(cnpj string) bool {
	clean := strings.ToUpper(reSep.ReplaceAllString(cnpj, ""))
	if !reCNPJ.MatchString(clean) || allSame(clean) {
		return false
	}
	w1 := []int{5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2}
	w2 := []int{6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2}
	d1 := dv(clean[:12], w1)
	d2 := dv(clean[:12]+string(rune('0'+d1)), w2)
	return d1 == int(clean[12]-'0') && d2 == int(clean[13]-'0')
}

// IsValidCNPJ("12.ABC.345/01DE-35") -> true  (alfanumérico, exemplo SERPRO)
// IsValidCNPJ("11.222.333/0001-81") -> true  (numérico)

O mesmo código valida os dois formatos: o numérico é um caso particular do alfanumérico. A base tem 12 posições (letras A–Z ou dígitos 0–9) e os 2 verificadores são sempre numéricos.

Por que ASCII − 48

No módulo 11 cada posição vira um número antes de multiplicar pelo peso. Para tratar letra e dígito de forma uniforme, converte-se o caractere pelo seu código menos 48: '0' vira 0, '9' vira 9 e 'A' vira 17 (segue até 'Z' = 42). É exatamente o que int(base[i]) - 48 faz dentro de dv. Os pesos vêm em duas listas (w1 para o 1º dígito, w2 para o 2º) e o resto da divisão por 11 define o verificador: r >= 2 ? 11 - r : 0. É o módulo 11 de sempre, só com a entrada normalizada.

publicidade

Cuidados

  • Precisa de strings.ToUpper. O regex aceita A–Z maiúsculo, então a base é normalizada antes da checagem. Sem o ToUpper, um CNPJ alfanumérico digitado em minúsculas seria reprovado — é um ponto fácil de esquecer ao portar de outras linguagens.
  • Repetidos não vão por regex. O regexp do Go usa RE2, que não suporta backreference — um padrão como ^(.)\1{13}$ nem compila. A função allSame faz o mesmo papel, comparando cada caractere com o primeiro, e descarta sequências como 00000000000000.
  • Regex só valida formato. O reCNPJ confirma 12 posições alfanuméricas + 2 dígitos, mas não confere o verificador — quem faz isso é a função acima. Veja regex de CNPJ.
  • Válido ≠ existe. A função confirma a consistência matemática, não se o CNPJ foi emitido a uma empresa real. Para isso é outra coisa: CNPJ válido vs. CNPJ real.
  • Alfanumérico entra em jul/2026 (IN RFB nº 2.229/2024), só para novos registros. O código já está pronto para os dois formatos.

Continue

Perguntas frequentes

A mesma função valida CNPJ numérico e alfanumérico?
Sim. A conversão ASCII − 48 trata letra e dígito de forma uniforme, então o numérico é um caso particular do alfanumérico — um só caminho valida os dois.
Por que o código tem <code>strings.ToUpper</code>?
Para normalizar a base antes do regex e do cálculo: o padrão aceita A–Z maiúsculo, então um CNPJ digitado em minúsculas seria reprovado sem o ToUpper.
Por que repetidos são pegos por <code>allSame</code> e não por regex?
O regexp do Go usa RE2, que não tem backreference. Um padrão como ^(.)\1{13}$ não compila — a checagem manual com allSame faz o mesmo papel.
Válido é o mesmo que existir?
Não. A função confere a consistência matemática (os verificadores), não se o CNPJ foi emitido a uma empresa real.
Código verificado por transliteração contra o núcleo, inclusive o exemplo oficial SERPRO (12ABC34501DE → DV 35). Algoritmo módulo 11 com ASCII−48. Revisado em 06/2026.