Documentos brasileiros8 min de leitura

Placa Mercosul e placa antiga: o que muda na validação, no banco e na busca

Os dois padrões convivem e vão conviver por muitos anos. Veja a estrutura de cada um, a expressão regular que aceita ambos, os erros de OCR com caracteres ambíguos e como normalizar a placa para busca.

Publicado em

AL

Por André Leitão

Desenvolvedor de software

O sistema aceitava placa há anos com uma expressão regular de três letras e quatro números. Aí chegou o primeiro veículo com placa Mercosul, o cadastro recusou, e a descoberta veio pelo suporte. É a história de praticamente todo sistema de frota, seguradora, estacionamento e controle de acesso no Brasil.

O problema tem uma característica que o torna mais chato do que difícil: a mudança é pequena, cabe em uma linha de código, e está espalhada por dezenas de lugares — validação, máscara, busca, relatório, integração e leitura automática de imagem.

Os dois padrões, lado a lado

Estrutura de cada padrão de placa
PosiçãoPadrão antigoPadrão Mercosul
1LetraLetra
2LetraLetra
3LetraLetra
4NúmeroNúmero
5NúmeroLetra
6NúmeroNúmero
7NúmeroNúmero
ExemploABC1234ABC1D23
SeparadorHífen por convençãoNenhum

A única mudança estrutural está na quinta posição. Essa economia é deliberada: ela multiplica por vinte e seis o espaço de combinações mantendo o mesmo número de caracteres, o que preserva o tamanho físico da placa e a compatibilidade de campos de sete posições já existentes.

A validação que aceita os dois

A tentação é usar uma expressão frouxa, de sete caracteres alfanuméricos. Ela aceita os dois padrões e também aceita 1234567 e AAAAAAA, o que devolve para o banco a responsabilidade de recusar lixo.

Validação estrita dos dois padrões
const PADRAO_ANTIGO = /^[A-Z]{3}\d{4}$/;
const PADRAO_MERCOSUL = /^[A-Z]{3}\d[A-Z]\d{2}$/;

export function normalizarPlaca(entrada) {
  // Remove hífen, espaço e qualquer outro separador; a placa é sempre maiúscula.
  return String(entrada).toUpperCase().replace(/[^A-Z0-9]/g, "");
}

export function validarPlaca(entrada) {
  const placa = normalizarPlaca(entrada);
  return PADRAO_ANTIGO.test(placa) || PADRAO_MERCOSUL.test(placa);
}

export function padraoDaPlaca(entrada) {
  const placa = normalizarPlaca(entrada);
  if (PADRAO_MERCOSUL.test(placa)) return "mercosul";
  if (PADRAO_ANTIGO.test(placa)) return "antigo";
  return null;
}

Separar as duas expressões, em vez de fundi-las numa só, tem uma vantagem prática: a função que identifica o padrão permite exibir o formato correto na interface e gerar relatórios sobre quantos veículos da frota já migraram.

Armazenamento e busca

A regra é a mesma dos outros documentos: guarde a forma normalizada e formate na exibição. Uma base em que a mesma placa aparece como ABC-1234, ABC 1234 e abc1234 produz duplicatas, quebra junções e faz a busca falhar de formas difíceis de reproduzir.

Exibição por padrão, armazenamento sempre normalizado
export function formatarPlaca(placa) {
  const normalizada = normalizarPlaca(placa);

  // O padrão Mercosul não usa separador; o antigo, por convenção, usa hífen.
  if (PADRAO_MERCOSUL.test(normalizada)) return normalizada;
  if (PADRAO_ANTIGO.test(normalizada)) {
    return `${normalizada.slice(0, 3)}-${normalizada.slice(3)}`;
  }
  return normalizada;
}

Caracteres ambíguos e leitura automática

Se o seu sistema recebe placa por reconhecimento de imagem — cancela de estacionamento, pedágio, fiscalização, aplicativo de vistoria — um problema novo aparece: alguns caracteres são visualmente quase idênticos.

Pares que o reconhecimento óptico confunde
ParConfusãoAgravante no padrão Mercosul
O e 0Muito altaA quinta posição virou letra, então 0 lido ali é sempre erro
I e 1AltaA primeira posição é sempre letra; 1 ali é erro certo
B e 8MédiaDepende da fonte e do ângulo
S e 5MédiaAgrava com placa suja ou desgastada
Z e 2BaixaAparece com baixa resolução

A boa notícia é que a estrutura do padrão elimina boa parte da ambiguidade: como cada posição tem tipo definido, um dígito lido onde só cabe letra é necessariamente erro, e pode ser corrigido pela posição.

Correção de leitura pela posição do caractere
const PARA_LETRA = { "0": "O", "1": "I", "5": "S", "8": "B", "2": "Z" };
const PARA_NUMERO = { O: "0", I: "1", S: "5", B: "8", Z: "2" };

// Posições que devem ser letra em cada padrão.
const LETRAS_ANTIGO = [0, 1, 2];
const LETRAS_MERCOSUL = [0, 1, 2, 4];

function corrigirPorPosicao(placa, posicoesDeLetra) {
  return placa
    .split("")
    .map((caractere, indice) => {
      const deveSerLetra = posicoesDeLetra.includes(indice);
      if (deveSerLetra) return PARA_LETRA[caractere] ?? caractere;
      return PARA_NUMERO[caractere] ?? caractere;
    })
    .join("");
}

Onde a mudança costuma passar despercebida

  • Campos com inputmode numérico, que no celular abrem um teclado sem letras.
  • Máscaras que forçam número na quinta posição e apagam a letra conforme o usuário digita.
  • Relatórios e filtros com expressão regular própria, escrita antes do padrão novo.
  • Layouts de arquivo trocados com parceiros, cuja validação está do outro lado.
  • Índices e chaves construídos sobre a placa formatada com hífen.
  • Testes automatizados cuja massa só contém placas do padrão antigo.

O último item é o que mantém o problema invisível por mais tempo: a suíte passa, porque nenhum caso de teste usa o formato novo. Incluir placas dos dois padrões na massa é a mudança de menor custo e maior retorno.

Gerando placas para teste

O gerador de placa do Codigio Labs produz valores nos dois padrões, respeitando a estrutura de cada um. Eles são fictícios e não correspondem a veículos registrados, o que os torna adequados para preencher cadastros de teste, exercitar máscaras e montar a massa que faltava na sua suíte.

Resumo

  • O Mercosul muda apenas a quinta posição, de número para letra; o resto da estrutura é idêntico.
  • Os dois padrões convivem por tempo indeterminado, porque a troca é por evento e não por prazo.
  • Valide com duas expressões separadas, o que também permite identificar o padrão.
  • Guarde a placa normalizada, em maiúsculas e sem separador, e formate só na exibição.
  • Em leitura automática, use a estrutura de posições para corrigir caracteres ambíguos — na busca, nunca no valor gravado.

Perguntas frequentes

A placa antiga deixou de valer?
Não. A substituição acontece por evento — transferência, mudança de município, dano à placa — e não por prazo geral. Isso significa que os dois padrões circulam simultaneamente e que qualquer sistema de cadastro precisa aceitar ambos por tempo indeterminado.
Qual a estrutura da placa Mercosul?
Sete caracteres, na ordem letra, letra, letra, número, letra, número, número. A diferença em relação ao padrão antigo está na quinta posição, que era um número e passou a ser uma letra — as demais posições mantêm o mesmo tipo.
A placa Mercosul usa hífen?
Não. A representação oficial é contínua, sem separador. O hífen do padrão antigo era uma convenção de escrita, e mantê-lo no armazenamento só cria variações do mesmo valor no banco.
Como lidar com O e 0 em leitura automática?
Guardando a placa lida e uma forma canônica para busca, em que os caracteres ambíguos são normalizados. Assim uma leitura que trocou O por 0 ainda encontra o registro, sem que você precise corromper o valor original.
Placas de outros países do Mercosul aparecem no meu sistema?
Podem aparecer em cadastros de fronteira e de transporte internacional. Os países adotaram o padrão comum com estruturas próprias, então uma validação rígida para o formato brasileiro rejeita veículos legítimos nesses contextos.

Ferramentas relacionadas

AL

Sobre o autor

Desenvolvedor de software no Brasil. Mantém o Codigio Labs desde a primeira ferramenta, escreve os artigos do site e revisa os textos quando a informação técnica muda.

Encontrou um erro ou tem uma correção a sugerir? Fale com o Codigio Labs. Correções relevantes são aplicadas com atualização da data de revisão do texto.

Continue lendo