Combinando caracteres no UTF-8

Eu já escrevi artigos falando de Unicode por aqui. Até citei, em um deles, que uma das grandes vantagens do UTF-8 é a composição de caracteres, aqui, mas não expliquei como se faz! Quer dizer, até expliquei… no antigo blog Lost in the e-Jungle, que não existe mais há anos!

UTF-8 é o padrão de máquinas que rodam sob o Linux e ele é parte do padrão Unicode. Esse padrão permite o uso, teórico, de cerca de 2 bilhões de caracteres diferentes (31 bits). Mas, esse valor teórico por ser, teóricamente, aumentado através de composição…

Composição, aqui, é o ato de criar um novo caracter a partir da combinação de dois ou mais. Por exemplo, se você quiser colocar um cículo em torno de uma letra, assim: A⃝ . Basta digitar o caracter ‘A’, seguido de Ctrl+u+20DD (e <enter>, no Linux, é claro!). O caracter de código U+20DD é um dos caracteres de combinação “diacrítica”. De fato, você pode também aplicar diversas combinações cascateadas… Por exemplo: x̺⃗ (com a setinha de vetor no topo e uma “ponte” embaixo) foi construído com o caracter ‘x’, seguido dos caracteres U+20d7 e U+033A, ambos “combining”…

Existem 5 grupos de caracteres combining do padrão UNICODE, como pode ser visto nesse grab de tela do character map do GNOME:

Grupos de combinação do UNICODE.
Grupos de combinação do UNICODE.

Mas estes não são os únicos. Outros grupos também apresentam seus próprios caracteres “combining”, como o grupo musical, por exemplo:

Grupo musical.
Grupo musical com combining character selecionado.

Você pode reparar que, mesmo que existam caracteres de combinação, eles, às vezes, estão presentes de forma já combinada. É o caso do caracter U+1D15F (𝅘𝅥), que pode ser construído com a combinação do caracter U+1D158 (𝅘) com o caracter U+1D165 (a barra vertical logo depois da semifusa ‘𝅘𝅥𝅲’), como neste exemplo: 𝅘𝅥. Acredite em mim… esse último caracter é composto por 2 caracteres! Para ficar mais claro, eis um dump hexadecimal com os 2 caracteres (as duas semimínimas 𝅘𝅥), em linhas separadas:

00000000  f0 9d 85 9f 0a f0 9d 85 98 f0 9d 85 a5 0a

Os bytes 0x0a são os saltos de linha. Embora, gráficamente, os dois caracteres ‘𝅘𝅥’ sejam idênticos, o segundo ocupa o dobro de espaço por usar um caracter “combined” extra.

Neste ponto você pode estar confuso a respeito da codificação dos caracteres. Afinal, “\xf0\x9d\x85\x9f” não se parece em nada com 0x1d15f, né? Acontece que UTF-8 codifiica grupos de caracteres de forma diferente… Apenas a sequẽncia de caracteres correspondentes ao ANSI é codificada com apenas 1 byte. Os outros grupos precisam de bits de controle adicionais. Eis a tabela com essa codificação (‘x’ são os bits do código original):

Codificação binária do UTF-8.
Codificação binária do UTF-8.

Assim, U+1d15f cai na faixa de 4 bytes de tamanho. Este valor, em binário é 0000111010001010111112 que, dividindo para cada byte e usando a máscara de codificação de acordo com a tabela acima, teremos: 11110000 10011101 10000101 10011111, ou seja, a sequência “\xf0\x9d\x85\x9f”, de acordo com dump que mostrei anteriormente.

Note que um únco caracter “normal” pode ter de 1 a 6 bytes de tamanho, adicione a isso os caracteres de combinação e você pode ter um único caracter com, talvez, uns 18 bytes (dependendo da combinação, é claro!).

Isso é meio que “o inferno” para certos desenvolvedores… Por um lado, há vantagem em podermos usar quaisquer tipos de símbolos numa string, visto que a string continuará terminando por um caracter ”… Mas, por outro lado, para fazermos comparações a coisa complica bastante. Vide os dois tipos de semimínima (𝅘𝅥) que mostrei acima.

Uma brincadeira, que agora tornou-se clássica, especialmente entre desenvolvedores para Linux ou javascript, é substituir o caracter ‘;’ que termina todo statement, pelo caracter ‘;’ (U+037A), que é o caracter grego de interrogação! Sente-se e assista ao desespero do desenvolvedor ao compilar o código!

O pesadelo não pára por ai… graças à composição, caracteres acentuados como ‘á’ podem ser codificados a partir do caracter pré-composto (U+00E1, como ao lado) ou pela sequência composta por ‘a’ (U+0041) e um caracter de acentuação aguda, de composição (U+0301), como este aqui: ‘á’. Graficamente eles são iguais, mas são sequências completamente diferentes de bytes. Infelizmente, se você quiser manter o recurso de usar quaisquer caracteres que quiser (Unicode) terá que lidar com esse tipo de coisa.

Anúncios

Deixe um comentário

Faça o login usando um destes métodos para comentar:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s