Manuseando acentos em strings: o guia prático
Acentos são um problema real em desenvolvimento. Todo mundo que já tentou fazer upload de um arquivo, salvar um nome em um banco de dados ou indexar texto para busca sabe que ç, ã, é e ô podem quebrar queries inteiras se você não tratar antes.
Para que serve os acento na prática
O acento existe na língua para distinção semântica e correta pronúncia. Em código, ele existe basicamente como um obstáculo até você aprender a lidar com ele. Ferramentas como o Unidec, normalize-java ou bibliotecas equivalentes em Python (unicodedata), PHP (Transliterator), JavaScript (Intl.Segmenter ou regex customizada) servem exatamente para transformar texto acentuado numa forma ASCII compatível com sistemas que não tratam Unicode adequadamente. Vou dar um exemplo direto. Recentemente precisei migrar uma base de 40 mil registros de nomes de clientes de um MySQL 5.6 para um PostgreSQL 14. O problema era que o MySQL usava collation latin1_swedish_ci que tratava "São Paulo" e "Sao Paulo" como iguais, mas o Postgres com UTF8 default não fazia essa equivalência. Queries de busca quebravam e relatórios cruzados retornavam resultados duplicados. A solução que funcionou foi normalizar os nomes antes do insert usando transliteração, convertendo çc, ãa, ée etc. Levei cerca de 3 horas para escrever o script de migração com tratamento de casos edge, e o resultado foi estável por meses.
Métodos de normalização
Existem três abordagens principais que eu vejo no dia a dia:
1. Transliteração com table-based mapping
Você cria um mapa de substituição caractere por caractere. Simples, rápido, funciona para a maioria dos casos. Em Python seria algo como: import unicodedata
def remover_acentos(texto):
nfkd = unicodedata.normalize('NFKD', texto)
return ''.join(c for c in nfkd if not unicodedata.combining(c))
O NFKD primeiro decompõe os caracteres compostos em suas partes básicas (uma 'é' vira 'e' + combinador de acento agudo), depois você filtra os combinadores. O resultado é puro ASCII.
2. Collation sensível no banco de dados
Em vez de transformar os dados, você configura o banco para tratar acentos corretamente durante comparações. No PostgreSQL, por exemplo, você pode criar uma collation personalizada ou usar a extensao unaccent: SELECT * FROM clientes WHERE unaccent(nome) = unaccent('são paulo');
No MySQL, o jeito é configurar a coluna ou conexão com utf8mb4_unicode_ci que, apesar do nome, ainda tem limitações importantes que vou explicar abaixo.
👉 Clique no botão abaixo para saber mais sobre o assunto!
3. Regex direta para casos simples
Para projetos pequenos onde você não quer depender de biblioteca externa, uma regex cobre o básico: [áàâãäå] a
[éèêë] e
[íìîï] i
[óòôõö] o
[úùûü] u
ç c
Funciona. Mas só funciona se o texto estiver nos caracteres que você mapeou. Caso um nome venha com um caractere raro, a regex simplesmente ignora e o dado fica inconsistente.
Pegadinhas que ninguém conta
A primeira coisa que quase todo mundo erra: normalização vs. transliteração não são a mesma coisa. Normalização (NFC, NFD, NFKC, NFKD) é um padrão Unicode. Ele redefine como os caracteres são codificados internamente, mas pode preservar acentos. Transliteração é substituição baseada em regras fonéticas. Se você só aplica NFC sem remover os combinadores, o resultado ainda tem acentos e o problema continua. Já vi gente passar dias debugando queries porque achava que o normalize() resolveu quando na verdade só mudou a representação binária do caractere.
A segunda pegadinha é o caso do ç versus c. Sistemas que tratam "ç" e "c" como equivalentes geralmente fazem isso via collation, não via normalização pura. O Postgres com collation padrão UTF8 trata "caça" e "casa" como strings diferentes em ORDER BY e comparação. Se seu sistema precisa de sensibilidade acentual zero, você precisa de unaccent() ou similar explicitamente. Terceiro ponto crítico: índice com acento. Se você indexa colunas com texto acentuado para busca full-text e depois normaliza o texto consultado sem normalizar também os dados indexados, a busca retorna zero resultados. Eu vi isso acontecer em um sistema de e-commerce que usava Elasticsearch com analyzer padrão. Os produtos cadastrados com nomes em português nunca apareciam nas buscas com acento. A correção foi criar um custom analyzer com char_filter de transliteração antes do tokenizador.
Quando a normalização não resolve
Existem cenários onde remover acentos é simplesmente a abordagem errada: — Nomes próprios: "São Paulo" virando "Sao Paulo" pode destruir a identidade do registro. Se o negócio depende de correspondência exata, normalizar pode ser prejuízo.
— Buscas que dependem de distinção: Em português, "para" e "prá" são grafias diferentes. Remover acentos fusiona palavras que não deveriam ser fundidas. — Dados multilingues: Se o sistema atende espanhol, português e francês, tabelas de transliteração por língua separada são necessárias. Uma tabela genérica perde nuances de cada idioma.
— Performance em grandes volumes: Normalização em tempo real em queries com milhões de linhas pode degradar significativamente. Pré-processamento em batch é quase sempre a melhor opção.
Alternativa quando tudo falha
Se o seu problema é puramente de ordenação e busca e você não quer transformar os dados, a melhor saída é configurar a collation corretamente desde o início. Não adianta normalizar dados que já estão produ