Inspetor de caracteres Unicode

Decompõe o texto nos seus pontos de código com nomes, categorias, blocos e codificações, e assinala caracteres invisíveis, bidi e sósias.

Entrada

O que esta ferramenta faz

Cole qualquer texto e ele volta decomposto nos caracteres individuais de que é realmente feito. Cada um recebe o seu nome Unicode, o seu número U+, que espécie de caractere é, a que sistema de escrita e a que bloco pertence, os bytes que ocupa em UTF-8 e UTF-16, e a sequência de escape que exige em seis formatos diferentes.

A maioria das pessoas chega aqui porque alguma coisa não bate certo. Uma cadeia é mais longa do que parece, dois valores que aparecem idênticos recusam-se a ser iguais, um nome de utilizador foi rejeitado por causa de caracteres que parecem letras normais, ou uma linha de código lê-se de forma diferente da que se comporta. As quatro têm a mesma forma: um caractere a fazer algo que o ecrã não mostra.

Caracteres, pontos de código e grafemas

A palavra «caractere» significa pelo menos três coisas diferentes, e confundi-las é onde começa quase toda a confusão à volta do Unicode. Um ponto de código é um valor do padrão Unicode, escrito U+0041 ou U+1F600. Um grafema é o que quem lê conta como um caractere. Muitas vezes não são o mesmo número.

  • Um «a» simples é 1 grafema, 1 ponto de código e 1 unidade UTF-16 — tudo coincide.
  • U+00E9, o é pré-composto, é 1 grafema, 1 ponto de código e 1 unidade UTF-16.
  • U+0065 U+0301, a mesma letra escrita como e mais um acento combinante, é 1 grafema mas 2 pontos de código e 2 unidades UTF-16.
  • U+1F600, a cara sorridente, é 1 grafema e 1 ponto de código mas 2 unidades UTF-16 — vive acima do BMP, por isso o JavaScript guarda-o como par substituto.
  • O emoji de família é 1 grafema, 5 pontos de código e 8 unidades UTF-16: três pessoas unidas por dois unificadores invisíveis.

O emoji de família é o caso que apanha as pessoas. Parece uma coisa só, o JavaScript relata comprimento 8, e uma coluna de base de dados de 5 caracteres não o suporta. Esta ferramenta agrupa os pontos de código sob o grafema que constroem, para que ambas as leituras estejam visíveis ao mesmo tempo em vez de terem de ser conciliadas de cabeça.

Os caracteres que não se conseguem ver

Um número surpreendente de caracteres Unicode não desenha absolutamente nada. Existem para controlar como o texto à sua volta se comporta e, como não deixam marca, sobrevivem a copiar, colar e rever sem que ninguém repare. São estes que a ferramenta aponta em vez de se limitar a listar:

  • Espaço, unificador e não-unificador de largura zero (U+200B, U+200D, U+200C) — sem largura, sem marca, e quebram toda a comparação de cadeias em que tocam.
  • Hífen opcional (U+00AD) — uma sugestão de onde uma palavra pode partir, invisível até acontecer.
  • Espaço inquebrável (U+00A0) — parece exatamente um espaço e é outro caractere, e é por isso que sobrevive tanto tempo em ficheiros de configuração.
  • Marca de ordem de bytes (U+FEFF) — fica muitas vezes no início de um ficheiro, onde se torna um primeiro caractere invisível do primeiro valor.
  • Controlos e imposições bidi (de U+202A a U+202E, de U+2066 a U+2069) — reordenam o texto à sua volta.

Os controlos bidi merecem menção à parte. Foram acrescentados para que o hebraico e o árabe possam misturar-se corretamente com texto latino, e desempenham bem essa função. Mas uma imposição colocada dentro de um comentário ou de uma cadeia pode fazer com que uma linha de código apareça numa ordem completamente diferente da que o compilador lê — o que significa que um revisor pode aprovar código que faz outra coisa. Essa classe de truque é conhecida por Trojan Source, e é a razão por que esta ferramenta assinala cada controlo bidi separadamente dos restantes caracteres invisíveis.

Caracteres sósias e escritas misturadas

O Unicode contém muitos caracteres visualmente idênticos a letras ASCII que não o são. O а cirílico, o ο grego e o a latino ocupam pontos de código diferentes e desenham-se da mesma maneira na maioria dos tipos de letra. Um domínio ou um nome de utilizador construído com eles parece correto e aponta para outro sítio.

Assinalar cada sósia não-ASCII seria inútil: pintaria de vermelho cada palavra russa, grega ou hebraica, e um aviso que dispara com texto normal é um aviso que as pessoas aprendem a saltar. Por isso a regra aqui é a do padrão de segurança do Unicode — uma palavra é suspeita quando as letras lá dentro vêm de mais do que um sistema de escrita:

  • «paypal.com» escrito inteiramente em letras latinas: não há nada a dizer.
  • A mesma palavra com um er e um a cirílicos à frente do «ypal» latino: uma palavra, dois sistemas de escrita, assinalada.
  • Uma palavra russa inteira em cirílico: um só sistema de escrita, texto vulgar, não assinalada.
  • Uma frase japonesa que usa han, hiragana e katakana em conjunto: três escritas, um só sistema de escrita, não assinalada.

Este último caso é a razão por que a regra exige cuidado. O japonês escreve-se com três escritas ao mesmo tempo e o coreano mistura duas, pelo que um teste ingénuo de «mais do que uma escrita é suspeito» declararia ataque cada frase japonesa. As combinações que são genuinamente um só sistema de escrita são tratadas como uma, e é isso que mantém o aviso com sentido.

Normalização, ou porque duas cadeias idênticas diferem

Alguns caracteres podem escrever-se de mais do que uma maneira. A letra é ou o único ponto de código U+00E9 ou o par U+0065 U+0301 — um e simples seguido de um acento agudo combinante. Ambas se mostram de forma idêntica. Nenhuma está errada. Iguais não são.

A normalização é o processo de escolher uma grafia, e tem quatro formas. A NFC compõe sempre que pode e é o que a web assume por omissão; a NFD decompõe em vez disso. As duas formas K vão mais longe e dobram também os caracteres de compatibilidade — o A de largura inteira passa a um A simples, e a ligadura fi passa a fi — o que é útil para pesquisa e correspondência e com perdas para armazenamento.

O painel aqui mostra as quatro formas do que colar e marca quais delas diferem da entrada. Se nenhuma diferir, o texto já está normalizado e a discrepância que anda a perseguir está noutro sítio. Se algumas diferirem, encontrou-a.

Nomes, categorias, escritas e blocos

Cada caractere atribuído carrega quatro elementos de identidade, e respondem a perguntas diferentes. O nome é o próprio caractere. A categoria geral diz que espécie de coisa é — uma letra minúscula, uma marca combinante, um símbolo de moeda, um controlo de formato. A escrita é o sistema de escrita a que pertence. O bloco é o intervalo de pontos de código em que foi atribuído, o que é um facto organizativo e não linguístico.

Bloco e escrita confundem-se com facilidade e muitas vezes divergem. As letras latinas vivem em pelo menos meia dúzia de blocos, e um bloco pode conter caracteres de várias escritas. Quando quer saber «que alfabeto é este», a resposta é a escrita; quando quer saber «onde é que isto vive no padrão», é o bloco.

Os nomes, as escritas e os blocos são mostrados aqui em inglês em todas as línguas, deliberadamente. São identificadores definidos pelo padrão, não prosa — U+200D chama-se ZERO WIDTH JOINER no mundo inteiro, e traduzi-lo tornaria impossível procurá-lo.

Codificações e escapes

Um ponto de código é um número; só se torna bytes depois de escolhida uma codificação. O UTF-8 usa entre um e quatro bytes e deixa o ASCII inalterado, e foi por isso que venceu. O UTF-16 usa uma ou duas unidades de 16 bits, e é disso que são feitas as cadeias do JavaScript — razão por que o .length relata 2 para um único emoji.

U+0041   41              # UTF-8: um byte, igual ao ASCII
U+00E9   C3 A9           # UTF-8: dois bytes
U+20AC   E2 82 AC        # UTF-8: três bytes
U+1F600  F0 9F 98 80     # UTF-8: quatro bytes

Cada linha aqui dá também o caractere escrito como escape em JavaScript, JSON, HTML, CSS, URL e Python, pronto a copiar. Não são todos iguais, e acima do BMP a diferença conta: o JavaScript e o Python têm um escape por ponto de código e usam-no, ao passo que o JSON não tem nenhum e tem de soletrar um emoji como as suas duas metades substitutas.

Perguntas frequentes

Porque é que a minha cadeia é mais longa do que o número de caracteres que vejo?
Ou contém caracteres invisíveis, ou contém grafemas construídos a partir de vários pontos de código. Ambos são mostrados aqui: os caracteres invisíveis são assinalados, e os grafemas de vários pontos de código são agrupados para que veja o único caractere e os vários valores de que é feito.
Duas cadeias parecem idênticas e não são iguais. Porquê?
Normalmente normalização. Uma letra acentuada pode ser um ponto de código ou uma letra mais uma marca combinante, e ambas se desenham igual. Cole aqui cada cadeia e compare as listas de pontos de código, ou veja que formas de normalização diferem da entrada.
O que é um espaço de largura zero e como foi parar ao meu texto?
É um caractere sem largura e sem marca, usado para sugerir uma oportunidade de mudança de linha. Chega normalmente ao copiar texto de uma página web, de um editor de documentos ou de um cliente de conversação e, como nada é mostrado, sobrevive a todas as revisões até que algo compare cadeias e falhe.
Qual é a diferença entre um ponto de código e um caractere?
Um ponto de código é um valor Unicode. Um caractere no sentido corrente é um grafema — o que quem lê conta como um — e um grafema pode valer vários pontos de código. Um emoji de família são cinco pontos de código e um grafema.
Porque diz a ferramenta que alguns caracteres não têm nome?
Por quatro razões diferentes, e diz qual. Os substitutos e os pontos de código de uso privado não têm nome no padrão, os não atribuídos não têm nada para nomear, e um caractere de um bloco histórico raramente consultado tem um nome que esta versão não transporta: a tabela de nomes guarda os blocos de onde as pessoas realmente colam em vez de os enviar todos.
Um aviso de escritas misturadas é prova de um ataque?
Não. Significa que uma única palavra vai buscar as suas letras a mais do que um sistema de escrita, que é a forma de um nome forjado e também algo que o texto vulgar faz de vez em quando. É um motivo para olhar, não um veredicto.
Alguma coisa do que colo é enviada para um servidor?
Não. A base de dados de caracteres é descarregada com a página e tudo corre no seu navegador; nada do que escreve é carregado ou registado, e funciona sem ligação de rede.