cnpjcpf.
Código · Ruby

Validar CNPJ em Ruby

Uma só função valida o CNPJ numérico e o novo alfanumérico: a conversão ord − 48 é retrocompatível, então o mesmo módulo 11 serve para os dois.

A função

Uma só função valida o CNPJ numérico e o alfanumérico. O segredo é que cada caractere entra no módulo 11 como ord - 48: assim '0'..'9' viram 0..9 (retrocompatível) e 'A'..'Z' viram 17..42.

Ruby
W1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2].freeze
W2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2].freeze

def dv(base, w)
  s = w.each_with_index.sum { |p, i| (base[i].ord - 48) * p }
  r = s % 11
  r < 2 ? 0 : 11 - r
end

def valid_cnpj?(cnpj)
  cnpj = cnpj.gsub(%r{[./-]}, '').upcase
  return false unless cnpj.match?(/\A[A-Z0-9]{12}\d{2}\z/)
  return false if cnpj.chars.uniq.length == 1 # repetidos
  d1 = dv(cnpj[0, 12], W1)
  d2 = dv(cnpj[0, 12] + d1.to_s, W2)
  d1 == cnpj[12].to_i && d2 == cnpj[13].to_i
end

valid_cnpj?('12.ABC.345/01DE-35') # => true  (alfanumérico, exemplo SERPRO)
valid_cnpj?('11.222.333/0001-81') # => true  (numérico)
valid_cnpj?('11.222.333/0001-00') # => false

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 ord - 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 ASCII menos 48: '0' vira 0, '9' vira 9 e 'A' vira 17 (segue até 'Z' = 42). É exatamente o que base[i].ord - 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 ? 0 : 11 - r. É o módulo 11 de sempre, só com a entrada normalizada.

publicidade

Por que o exemplo SERPRO confere

A base oficial 12ABC34501DE produz DV 35: no 1º dígito a soma dá 459 (resto 8 → 11 - 8 = 3) e no 2º a soma dá 424 (resto 6 → 11 - 6 = 5). A função acima reproduz exatamente isso. Detalhe do cálculo em calcular o dígito verificador alfanumérico.

Cuidados

  • Só maiúsculas. O alfanumérico não aceita minúsculas — por isso a função faz .upcase antes de validar.
  • Os DV são sempre numéricos. A regex exige \d{2} no fim: letra nos dois últimos é inválido.
  • Sequências repetidas ('00000000000000') passariam no módulo 11, por isso a função as descarta antes com cnpj.chars.uniq.length == 1.
  • No banco, use texto. Colunas numéricas quebram com letras — guarde em CHAR(14)/VARCHAR.
  • Válido ≠ existe. A função confirma a matemática, não se a empresa está cadastrada na Receita. Para isso é outra coisa: CNPJ válido vs. CNPJ real.

Continue

Perguntas frequentes

O mesmo código valida o CNPJ alfanumérico?
Sim. A função valid_cnpj? converte cada caractere por ord − 48, então '0'..'9' viram 0..9 (retrocompatível) e 'A'..'Z' entram no mesmo módulo 11. O numérico é um caso particular do alfanumérico.
Os dígitos verificadores podem ser letras?
Não. Só a base de 12 posições aceita letras; os 2 DV finais são sempre numéricos. Por isso a regex termina em \d{2}.
Preciso de alguma gem?
Não. A função usa só a biblioteca padrão. Para projetos maiores, a gem cpf_cnpj (de fnando) já suporta o formato alfanumérico; brazilian_documents (de fidelisrafael) é outra opção.
Código verificado, inclusive contra o exemplo oficial do SERPRO (12ABC34501DE → DV 35). Algoritmo módulo 11 com ord−48. Revisado em 06/2026.