Porque é que aparece "ç" em vez de "ç"
Aparece num site antigo, numa importação de CSV, num email. E não é um caractere estranho — é a mesma letra, lida com a tabela errada.
1. O que se passa
Em UTF-8, o "ç" não cabe num byte: são dois, 0xC3 e 0xA7. Se alguém ler esses dois bytes como se fossem Latin-1 — uma tabela onde cada byte é uma letra — vê duas letras:
ç → UTF-8 → C3 A7 → lido como Latin-1 → çDaí o padrão. O "Ã" à frente de tudo é a assinatura de texto UTF-8 lido como se não fosse.
çeraçãeraãêeraê
2. Onde é que a tabela se perde
A cadeia tem muitos elos, e basta um estar errado:
A ligação à base de dados — o cliente diz um encoding e a tabela está noutro.
A coluna. Em MySQL,
utf8nunca foi UTF-8 a sério: são três bytes no máximo e não chega para emojis. O correto éutf8mb4.O cabeçalho da resposta:
Content-Type: text/html; charset=utf-8.O ficheiro CSV que o Excel gravou em Windows-1252 sem avisar ninguém.
3. O caso mau: dupla codificação
Acontece quando texto já estragado é guardado outra vez como UTF-8. Aí o "ç" vira ele próprio dois caracteres, e o estrago passa a ter camadas:
ç → ç → çReparar isto é desfazer as camadas pela ordem inversa — e é preciso saber quantas são. É por isso que a correção se faz uma vez, numa cópia, com contagem antes e depois.
// Desfazer uma camada: ler os bytes como Latin-1 e reinterpretar como UTF-8
const reparado = Buffer.from(estragado, 'latin1').toString('utf8');4. A prevenção
UTF-8 em todos os elos, sem exceção: base, ligação, ficheiros, cabeçalhos, editor. E validar no sítio onde os dados entram — é infinitamente mais barato recusar um ficheiro mal codificado do que reparar uma tabela seis meses depois, quando já ninguém sabe quantas camadas tem.