1001Ferramentas
🔤Validadores

Validador de UTF-8

Verifica se uma sequência de bytes (em hex) é UTF-8 válida — útil para depurar encoding de arquivos. Mostra o texto decodificado se válido.

UTF-8: a codificação de comprimento variável que virou padrão da web

O UTF-8 e a codificação de caracteres dominante na internet — em 2024 ja passa de 98% de todas as páginas. Desenhado por Ken Thompson e Rob Pike em 1992 e padronizado como RFC 3629 (2003), resolve um problema difícil de compatibilidade: codificar todo o catálogo Unicode (atualmente 154.998 code points atribuídos até U+10FFFF) mantendo-se compatível byte a byte com ASCII de 7 bits. Essa compatibilidade retroativa explica por que todo sistema operacional, navegador, banco e protocolo moderno adotou UTF-8 como default seguro.

Como o UTF-8 codifica um code point em 1 a 4 bytes

UTF-8 e uma codificação de comprimento variável. Um byte lider anuncia quantos bytes de continuacao vem depois, e cada byte de continuacao contribui com 6 bits adicionais de payload:

  • 1 byte0xxxxxxx — code points U+0000 a U+007F (ASCII puro).
  • 2 bytes110xxxxx 10xxxxxxU+0080 a U+07FF (latim estendido, grego, cirilico, hebraico, arabe).
  • 3 bytes1110xxxx 10xxxxxx 10xxxxxxU+0800 a U+FFFF (BMP — ideogramas chines/japones/coreano, maioria dos sistemas vivos).
  • 4 bytes11110xxx 10xxxxxx 10xxxxxx 10xxxxxxU+10000 a U+10FFFF (planos suplementares, emoji, escritas históricas).

Os bytes de continuacao começam sempre com o padrão 10, o que torna o fluxo auto-sincronizavel: um parser pode cair em qualquer posição e encontrar o próximo byte lider em até três passos. O português brasileiro fica na faixa de 2 bytes — á = C3 A1, é = C3 A9, ç = C3 A7, ã = C3 A3.

"Olá" -> 4F 6C C3 A1     (3 chars, 4 bytes)
"日本"  -> E6 97 A5 E6 9C AC (2 chars, 6 bytes)
"😀"   -> F0 9F 98 80       (1 char, 4 bytes)

O que torna uma sequência de bytes invalida

Um validador UTF-8 estrito rejeita seis famílias de sequências mal formadas:

  • Byte de continuacao solto — qualquer 10xxxxxx sem byte lider antes.
  • Sequência truncada — byte lider que promete 2/3/4 bytes mas não entrega todos.
  • Codificação overlong — codificar um code point com mais bytes do que o mínimo necessário (por exemplo C0 80 para NUL e proibido; algumas APIs Java antigas abusaram disso como "modified UTF-8").
  • Surrogate code pointsU+D800 a U+DFFF são reservados para pares substitutos do UTF-16 e nunca devem aparecer em UTF-8.
  • Code point fora do intervalo — qualquer coisa acima de U+10FFFF, que demandaria 5 ou 6 bytes (banido pela RFC 3629).
  • Bytes lideres inválidos0xC0, 0xC1, 0xF50xFF nunca podem começar uma sequência UTF-8 legitima.

Ferramentas de segurança dependem de validação estrita: overlong encodings ja foram usados para contrabandear path traversals ../ em filtros ingenuos (worm Nimda contra o IIS).

BOM, declaracoes e o header de charset

O Byte Order Mark em UTF-8 e o prefixo de três bytes EF BB BF (forma codificada de U+FEFF). Diferente de UTF-16, a ordem de bytes não tem significado em UTF-8, então o BOM e apenas um sinal — e opcional. A spec do HTML5 inclusive recomenda omiti-lo, enquanto muitas ferramentas Windows (Notepad, exports antigos de CSV do Excel) insistem em grava-lo. Servidores PHP antigos vazavam o BOM no início da resposta, quebrando chamadas header(); esse bug histórico e uma das razoes para "sem BOM" ser o default mais seguro.

Canais de declaração em ordem de prioridade:

  • Header HTTP: Content-Type: text/html; charset=UTF-8 — vence o documento.
  • <meta charset="UTF-8"> do HTML5 nos primeiros 1024 bytes do <head>.
  • Prologo XML: <?xml version="1.0" encoding="UTF-8"?>.
  • BOM como último recurso de detecção.

UTF-8 vs UTF-16 vs UTF-32 e o legado do ISO-8859-1 / Windows-1252

O UTF-16 usa 2 ou 4 bytes por code point e e o formato nativo de strings dentro do Windows, do Java e dos engines JavaScript (a V8 guarda strings em 16 bits internamente). Fora desses runtimes UTF-16 e raro porque não e compatível com ASCII e depende de endianness. O UTF-32 usa 4 bytes fixos — fácil indexar mas desperdica memória. O ISO-8859-1 (Latin-1) e o Windows-1252 são codificacoes legadas de byte único ainda presentes em bancos brasileiros antigos; converte-las para UTF-8 normalmente exige iconv ou ICU explicitos.

utf8 vs utf8mb4 no MySQL — a armadilha que comeu emoji

Até a versão 8 do MySQL, o alias utf8 era secretamente utf8mb3: somente até 3 bytes, o que silenciosamente quebrava emoji e code points suplementares. A correção e o alias utf8mb4 com collation utf8mb4_0900_ai_ci ou utf8mb4_unicode_520_ci. Sempre declare CHARACTER SET utf8mb4 no CREATE DATABASE, CREATE TABLE, no my.cnf, na URL JDBC e no SET NAMES da conexão — caso contrário a cadeia vaza para utf8mb3 em algum salto e corrompe os dados.

Mojibake, dupla codificação e como detectar

Mojibake e o lixo visível que surge quando bytes são decodificados com o charset errado. Sintoma clássico em português: "olá" renderizado como "olá" porque os bytes UTF-8 (C3 A1) foram lidos como Latin-1 e depois re-codificados em UTF-8. Heuristicas de detecção incluem checar sequências impossiveis (por exemplo C3 83 C2 A1 para "á"), rodar detectores como chardet / ICU e inspecionar a razão entre tamanho em bytes e número de caracteres. Esta ferramenta valida estritamente e mostra o detalhamento dos bytes para você identificar o problema na origem.

FAQ

O BOM e obrigatório em arquivos UTF-8? Não. A RFC 3629 e a spec do HTML5 recomendam omitir. So use se o consumidor exigir explicitamente (alguns fluxos de CSV no Excel para Windows).

Emoji precisa mesmo de 4 bytes? Sim, praticamente todos. Emoji vivem nos planos suplementares a partir de U+1F000, codificados em UTF-8 com a forma de 4 bytes. Modificadores de tom de pele e sequências ZWJ combinam vários code points de 4 bytes.

No MySQL escolho utf8 ou utf8mb4? Sempre utf8mb4. O alias "utf8" puro e um erro histórico e quebra silenciosamente emoji e caracteres suplementares.

Por que meu texto em português aparece como "?" ou "é" no banco? Charset mismatch na insercao. Ou a conexão esta com charset errado (defina charset=utf8mb4 no DSN) ou os dados ja chegaram em mojibake na origem. Conserte a pipeline e depois re-encode com iconv -f LATIN1 -t UTF-8 se necessário.

Um byte isolado pode ser UTF-8 válido? Apenas se estiver no intervalo 00–7F. Qualquer byte entre 80 e FF sozinho e inválido — precisa fazer parte de uma sequência multi-byte.

Ferramentas Relacionadas