Como lidar com texto com acento agudo e circunflexo em processamento de strings
A maioria dos problemas com acentuação acontece quando alguém tenta comparar strings ou fazer busca sem normalizar o texto primeiro. O resultado são comparações que falham de forma silenciosa e frustrante. Vou explicar o que acontece e como resolver, porque já perdi tempo demais caçando bugs que eram só acento.
texto com acento agudo e circunflexo na prática
O problema central é que letras acentuadas não são caracteres únicos na maioria dos sistemas. Quando você vê a letra "á", o computador pode estar vendo dois bytes: o "a" normal mais um código de combinação. Isso é normalização NFC versus NFD, e a confusão entre os dois formatos é a causa número um de erros de comparação em texto português. Um exemplo real que encontrei semana passada: estava validando um formulário onde o usuário digitava "São Paulo" com acento circunflexo no "ã". O sistema rejeitava porque a string vinha em NFD (combinada) e o banco de dados esperava NFC (pré-composta). A solução foi aplicar unicode.normalize("NFC", string) antes de qualquer comparação. Levei uns 20 minutos debugando isso porque o erro não aparecia nos logs.
Entendendo os acentos que você vai encontrar
Em português, os acentos agudos mais comuns são em á, é, í, ó, ú, ô, ô. Os circunflexos aparecem em â, ê, ô. A diferença entre os dois tipos de acento é puramente gráfica — o agudo indica sílaba tônica aberta, o circunflexo indica sílaba tônica fechada. Mas para processamento computacional, a distinção relevante é entre pré-composição e decomposição. Quando um texto está em NFC, cada letra acentuada é um único código Unicode. "Á" vira U+00C1. Em NFD, o mesmo "Á" se decompõe em "A" (U+0041) mais o acento agudo combinatório (U+0301). Dois bytes fazendo o trabalho de um. Isso existe por compatibilidade histórica com sistemas mais antigos.
Como normalizar antes de processar
A abordagem padrão é transformar tudo para NFC e remover acentos apenas se a comparação exigir. Vou mostrar com código em Python porque é a linguagem mais usada nesse tipo de tarefa: Passo 1: Normalizar para NFC
Use unicodedata.normalize("NFC", texto) em todas as strings que entram no sistema. Isso garante que "á" seja sempre o mesmo código, independente de como foi digitado. Sem isso, duas strings visualmente idênticas podem ter representação interna diferente. Passo 2: Remover acentos apenas para comparação
👉 Clique no botão abaixo para saber mais sobre o assunto!
Se o objetivo é busca ou equality check, use a técnica de decomposição seguida de filtragem: texto_normalizado = unicodedata.normalize("NFD", texto)
texto_sem_acentos = "".join(c for c in texto_normalizado if unicodedata.category(c) != "Mn")
O "Mn" aqui é a categoria Unicode de "Mark, Nonspacing" — ou seja, os acentos combinatórios que são removidos. O resultado é uma string pura, sem marcações diacríticas.
Pegadinhas que ninguém conta
A primeira pegadinha é o caso do "ç". Ele não tem versão decomposta em NFC. O "ç" (U+00E7) permanece igual em ambos os formatos, então não precisa de tratamento especial. Mas muitos desenvolvedores tratam o "c" como se fosse acentuado e acabam removendo o cedilha quando não deveria ser removido. A segunda pegadinha, e essa é mais séria, é a diferença entre normalização e transliteração. Normalizar converte caracteres; transliterar substitui por equivalentes não acentuados. Se você precisa salvar em um banco que não suporta Unicode, a normalização sozinha não resolve. Nesse caso, use str.encode("latin-1", "ignore").decode("latin-1") para mapear os acentos para sua forma latin-1, ou simplesmente remova-os com a técnica de decomposição acima.
Outro problema prático: ao remover acentos, "São Paulo" vira "Sao Paulo", mas "S\u00E3o Paulo" (em NFC) também vira "Sao Paulo". O problema é que em alguns sistemas, o usuário pode digitar usando IME ou copiar e colar de fontes diferentes, e a decomposição pode gerar resultados ligeiramente distintos para o mesmo caractere visual. Sempre normalice para NFC primeiro, depois para NFD, e só então remova os marcas.
Quando a normalização não ajuda
Existem cenários onde normalizar texto não resolve. Se o seu sistema usa regex com padrões fixos de acentuação, a normalização muda a string mas não o padrão. Nesse caso, você precisa adaptar o regex ou normalizar ambos os lados — o padrão e o texto de busca. Também não funciona para sistemas legados que indexam texto internamente em ASCII puro, porque a acentuação é perdida na leitura inicial. Se você está trabalhando com grandes volumes de texto e performance é crítica, a normalização em tempo real pode ser um gargalo. Nesse caso, normalizar uma vez durante o upload ou ingestão e armazenar ambas as versões (com e sem acento) é mais eficiente. Já vi sistemas onde a normalização sob demanda aumentava o tempo de resposta de 50ms para 300ms em queries de busca.
Resumo técnico rápido
Para resolver texto com acento agudo e circunflexo de forma confiável, a sequência correta é: normalizar para NFC, depois decompor para NFD, filtrar marcas não espaçadoras (categoria Mn), e comparar ou buscar na versão limpa. Para exibição, mantenha a versão NFC original. Isso cobre 99% dos casos práticos em português brasileiro e europeu.