Contador de bytes UTF-8 | Identifique a divergência entre VARCHAR e String.length em uma única tela
Cole um texto e veja simultaneamente os bytes UTF-8, pontos de código Unicode (caracteres reais), unidades de código UTF-16 (o valor que string.length retorna em JavaScript) e o número de linhas. O detalhamento em 4 categorias (ASCII, Latim estendido, BMP CJK, emoji e planos suplementares) mostra exatamente quais caracteres estão inflando seu orçamento de armazenamento.
💡 Sobre esta ferramenta
Se você já recebeu ERROR 1406: Data too long for column ao inserir um nome com til, percebeu que um JWT contendo emoji quase dobra de tamanho, ou descobriu no console que '😀'.length === 2, você esbarrou na diferença entre pontos de código Unicode, bytes UTF-8 e unidades UTF-16.
UTF-8 é uma codificação de comprimento variável definida pelo RFC 3629: ASCII cabe em 1 byte, o Latim estendido (ã, ç, é, õ), grego e cirílico em 2, o bloco BMP CJK em 3, e tudo acima de U+FFFF — emoji, ideogramas suplementares, símbolos matemáticos — em 4 bytes. As strings de JavaScript, por outro lado, vivem internamente em UTF-16, então qualquer caractere fora do BMP aparece como par substituto (surrogate pair) e conta como 2 em length. Resultado: bancos de dados medem em bytes, APIs de JS raciocinam em unidades UTF-16 e nós humanos contamos em grafemas. As três medidas divergem assim que um emoji ou caractere exótico entra em cena.
Esta ferramenta exibe as quatro métricas lado a lado e classifica cada caractere em um dos quatro buckets de bytes UTF-8, permitindo responder perguntas práticas: "Por que um texto em português pesa mais que a versão em inglês?", "Quantos emoji cabem em uma chave Redis de 4 KB?", "Meu display_name cabe nesta coluna NVARCHAR(50)?".
🧐 Perguntas frequentes
Q. VARCHAR(255) significa 255 caracteres ou 255 bytes?
A. No MySQL 5.0.3 ou superior são 255 caracteres, mas o limite de tamanho de linha é calculado em bytes (65.535 por linha). Com utf8mb4, um VARCHAR(N) é tratado como podendo ocupar até N × 4 bytes nos cálculos de índice e linha — portanto uma única coluna VARCHAR(16383) já preenche a linha inteira. Use o campo "Bytes UTF-8" desta ferramenta para dimensionar colunas com dados reais.
Q. Por que '😀'.length retorna 2 em JavaScript?
A. String.prototype.length retorna unidades de código UTF-16. U+1F600 fica fora do BMP, então é codificado como o par substituto 😀. Para contar caracteres reais, use [...string].length, Array.from(string).length ou o campo "Caracteres" desta ferramenta, que itera pontos de código com for..of.
Q. Qual a diferença entre utf8 e utf8mb4 no MySQL?
A. O charset legado utf8 armazena no máximo 3 bytes por caractere e converte silenciosamente qualquer caractere de 4 bytes (emoji, vários ideogramas suplementares, símbolos matemáticos) em ?. utf8mb4 é o UTF-8 completo conforme o RFC 3629. Para novos esquemas escolha sempre utf8mb4: se o bucket "4 bytes" desta ferramenta tiver qualquer valor, o charset legado teria destruído seus dados.
Q. Caracteres vs unidades UTF-16: quando isso importa?
A. Em qualquer API que confia em string.length: props key do React, truncamento ingênuo com substring, validadores de comprimento de senha, limites do Twitter antes de 2017. Grafemas (👨👩👧👦 = um único caractere percebido) também diferem de pontos de código; use Intl.Segmenter quando precisar de contagem voltada ao usuário final.
Q. Como são contadas as quebras de linha?
A. LF (\n), CRLF (\r\n) e CR (\r) são todos tratados como um único separador de linha. Uma entrada vazia equivale a 0 linhas; qualquer entrada não vazia equivale a pelo menos 1. Observação: CRLF ainda ocupa 2 bytes e 2 unidades UTF-16 mesmo contando como um separador único.
📚 Curiosidades
- A herança do latin1 no Brasil: Sistemas brasileiros nascidos nos anos 2000 — bancos legados de varejo, ERPs financeiros, ginecologia de prontuários eletrônicos antigos — frequentemente usavam
latin1, onde cada caractere, incluindoã,ç,é, ocupava 1 byte. A migração parautf8mb4fez essas mesmas letras passarem a ocupar 2 bytes, e queries que confiavam emLENGTH(coluna)para validar tamanho começaram a falhar. O padrão correto éCHAR_LENGTH(coluna), e esta ferramenta mostra de relance qual das duas grandezas interessa. - Português europeu vs brasileiro: PT-PT usa formas como
direcção,acção,colectivo(comcantes dot), enquanto PT-BR adotoudireção,ação,coletivoapós o Acordo Ortográfico de 1990. PT-PT também usa mais oçe o trema (üantes da reforma). Em termos de bytes, um texto PT-PT clássico tende a ser ligeiramente mais pesado por trazer mais ligaduras e acentos preservados. Cole um trecho em cada variante e compare o bucket "2 bytes" — a diferença é pequena mas visível. - Caracteres regionais e WhatsApp: O WhatsApp Brasil registra um dos maiores volumes globais de mensagens, e cerca de 70% delas contém pelo menos um emoji ou figurinha. Cada emoji padrão adiciona 4 bytes UTF-8 + 2 unidades UTF-16; "Oi 😊👍🎉" ocupa 15 bytes contra 2 bytes de "Oi". Para SMS-gateways e push notifications com APNS, onde a cota de bytes é estrita, esse acréscimo é sentido imediatamente em escala.