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 codificacao de comprimento variavel que virou padrao da web

O UTF-8 e a codificacao de caracteres dominante na internet — em 2024 ja passa de 98% de todas as paginas. Desenhado por Ken Thompson e Rob Pike em 1992 e padronizado como RFC 3629 (2003), resolve um problema dificil de compatibilidade: codificar todo o catalogo Unicode (atualmente 154.998 code points atribuidos ate U+10FFFF) mantendo-se compativel 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 codificacao de comprimento variavel. 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 historicas).

Os bytes de continuacao comecam sempre com o padrao 10, o que torna o fluxo auto-sincronizavel: um parser pode cair em qualquer posicao e encontrar o proximo byte lider em ate tres passos. O portugues 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 sequencia de bytes invalida

Um validador UTF-8 estrito rejeita seis familias de sequencias mal formadas:

  • Byte de continuacao solto — qualquer 10xxxxxx sem byte lider antes.
  • Sequencia truncada — byte lider que promete 2/3/4 bytes mas nao entrega todos.
  • Codificacao overlong — codificar um code point com mais bytes do que o minimo necessario (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 sao 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 invalidos0xC0, 0xC1, 0xF50xFF nunca podem comecar uma sequencia UTF-8 legitima.

Ferramentas de seguranca dependem de validacao 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 tres bytes EF BB BF (forma codificada de U+FEFF). Diferente de UTF-16, a ordem de bytes nao tem significado em UTF-8, entao 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 inicio da resposta, quebrando chamadas header(); esse bug historico e uma das razoes para "sem BOM" ser o default mais seguro.

Canais de declaracao 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 ultimo recurso de deteccao.

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 nao e compativel com ASCII e depende de endianness. O UTF-32 usa 4 bytes fixos — facil indexar mas desperdica memoria. O ISO-8859-1 (Latin-1) e o Windows-1252 sao codificacoes legadas de byte unico 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

Ate a versao 8 do MySQL, o alias utf8 era secretamente utf8mb3: somente ate 3 bytes, o que silenciosamente quebrava emoji e code points suplementares. A correcao 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 conexao — caso contrario a cadeia vaza para utf8mb3 em algum salto e corrompe os dados.

Mojibake, dupla codificacao e como detectar

Mojibake e o lixo visivel que surge quando bytes sao decodificados com o charset errado. Sintoma classico em portugues: "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 deteccao incluem checar sequencias impossiveis (por exemplo C3 83 C2 A1 para "á"), rodar detectores como chardet / ICU e inspecionar a razao entre tamanho em bytes e numero de caracteres. Esta ferramenta valida estritamente e mostra o detalhamento dos bytes para voce identificar o problema na origem.

FAQ

O BOM e obrigatorio em arquivos UTF-8? Nao. 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 sequencias ZWJ combinam varios code points de 4 bytes.

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

Por que meu texto em portugues aparece como "?" ou "é" no banco? Charset mismatch na insercao. Ou a conexao 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 necessario.

Um byte isolado pode ser UTF-8 valido? Apenas se estiver no intervalo 00–7F. Qualquer byte entre 80 e FF sozinho e invalido — precisa fazer parte de uma sequencia multi-byte.

Ferramentas Relacionadas