"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Unicode, Emojis e um pouco de Golang

Unicode, Emojis e um pouco de Golang

Publicado em 01/11/2024
Navegar:928

Unicode, Emojis, and a bit of Golang

Ultimamente, tive um problema com minha instalação do Fedora Linux exibindo emojis na interface do sistema operacional e nos navegadores. Esse problema me levou a investigar um pouco o projeto de configuração de fontes, mas para testar minhas configurações e fontes, precisei produzir emojis de todas as versões Unicode, o que eventualmente me levou a escrever um "script" Golang para imprimir todos os emojis e alguns informações sobre seus internos.

Ao longo desta viagem, mergulhei profundamente nos aspectos internos dos emojis, suas representações binárias e algumas das decisões estranhas/fofas tomadas pelo padrão Unicode em relação aos emojis.

Mas primeiro, vamos dar um passo atrás e resumir algum glossário.

Codificação (ou codificação de caracteres)

Poderíamos descrever a codificação como o "mapeamento" ou "tradução" entre uma letra de um idioma e a representação binária desta letra. Por exemplo, a codificação ASCII tradicional mapeia a letra a para 0x61 hexadecimal (0b01100001 binário). Exemplos de codificações são as páginas de código de 8 bits da Microsoft (Windows 125x) ou ISO (ISO/IEC 8859).

Nessas páginas de código fixas de 8 bits, a "quantidade" mínima de informações usadas é de 8 bits (1 byte), o que significa que elas podem conter 256 letras/caracteres diferentes. Diferentes páginas de código foram criadas reutilizando os 256 códigos binários para suportar vários idiomas. Portanto, ter um arquivo de texto com esses 3 bytes escritos nele [0xD0, 0xE5, 0xF2] é lido como "Πες" usando o ISO 8859-7 grego, ou "Ðåò" usando o ISO 8859-7 ocidental (mesmos bytes, interpretados de forma diferente com base na página de código).

Em algum momento, ter muitas páginas de código diferentes não foi bem dimensionado à medida que a tecnologia progredia. Portanto, precisávamos de algo que pudesse se adequar a todos os idiomas (e mais) e ser unificado em todos os sistemas.

[ avançando, deixando muita história e padrões de fora, até o presente ]

Padrão Unicode

O padrão Unicode foi projetado para oferecer suporte a todos os sistemas de escrita do mundo que podem ser digitalizados. Assim, usando o exemplo acima, nos padrões Unicode, a letra grega “Π” possui o código 0x03A0 enquanto a letra latina maiúscula eth “Д possui o código 0x00D0 e não colidem mais. O padrão Unicode tem versões e, no momento em que este artigo foi escrito, a versão mais recente era 16.0 (especificações).

Mas espere um minuto, o que é esse "ponto de código"?

Pontos de código Unicode

No padrão Unicode, cada "letra", caractere de controle, emoji e cada item definido em geral tem um valor binário exclusivo chamado "ponto de código". O padrão define todos os pontos de código e cada ponto de código contém informações puras de código/binário. O formato hexadecimal para cada ponto de código geralmente é escrito com um prefixo U. Por exemplo, o ponto de código grego com letras minúsculas Ômega (ω) é U 03C9.

Então, quem realmente codificamos esses pontos de código?

Formulários de codificação Unicode e esquemas de codificação

A primeira parte da codificação de Code Points em bytes é a Encoding Fomrs. De acordo com o padrão:

Os formulários de codificação

especificam como cada número inteiro (ponto de código) para um caractere Unicode deve ser expresso como uma sequência de uma ou mais unidades de código.

Formulários de codificação usam o termo "unidade de código" para se referir à menor unidade de dados usada para representar um ponto de código Unicode dentro de uma codificação específica.

O padrão Unicode define três formas de codificação diferentes:

  • UTF-32. Unidade de código de comprimento fixo por ponto de código. Tamanho por ponto de código: uma unidade de código de 32 bits (4 bytes).
  • UTF-16. Unidades de código de comprimento variável por ponto de código. Tamanho por ponto de código: uma ou duas unidades de código de 16 bits (2 ~ 4 bytes).
  • UTF-8. Unidades de código de comprimento variável por ponto de código. Tamanho por ponto de código: uma a quatro unidades de código de 8 bits (1 ~ 4 bytes).

Isso significa que um único ponto de código ou uma sequência de pontos de código pode ser codificado de forma diferente dependendo da forma de codificação usada.

A camada que cuida da serialização binária real em Unicode é chamada de Esquemas de Codificação e cuida de todos os detalhes de baixo nível (como endianness). Tabela 2-4 das especificações Unicode:


|Encoding Scheme| Endian Order                | BOM Allowed? |
| ------------- | ----------------------------| ------------ |
| UTF-8         | N/A                         | yes          |
| UTF-16        | Big-endian or little-endian | yes          |
| UTF-16BE      | Big-endian                  | no           |
| UTF-16LE      | Little-endian               | no           |
| UTF-32        | Big-endian or little-endian | yes          |
| UTF-32BE      | Big-endian                  | no           |
| UTF-32LE      | Little-endian               | no           |


Nota: Quase todas as linguagens de programação, sistemas operacionais e sistemas de arquivos modernos usam Unicode (com um de seus esquemas de codificação) como sua codificação nativa. Java e .NET usam UTF-16, enquanto Golang usa UTF-8 como codificação de string interna (isso significa que quando criamos qualquer string na memória, ela é codificada em Unicode com a forma de codificação mencionada)

Emoji

O padrão Unicode também define pontos de código para emojis (muitos deles) e (após alguma confusão com o número da versão), a versão do "padrão" Emoji progride em paralelo com o padrão Unicode. No momento em que este artigo foi escrito, temos Emoji "16.0" e Unicode Standard "16.0".

Exemplos:
⛄ Boneco de neve sem neve (U 26C4)
? Rosto sorridente com olhos sorridentes e três corações (U 1F970)

Modificadores de Emoji e adesão

Unicode define modificadores que podem seguir o ponto de código base de um emoji, como variação e tom de pele (não exploraremos a parte de variação).

Temos seis modificadores de tom de pele (seguindo a escala Fitzpatrick) chamados EMOJI MODIFIER FITZPATRICK TYPE-X (onde x é 1 a 6), e eles afetam todos os emojis humanos.

Tom de pele claro (Fitzpatrick Type-1-2) (U 1F3FB)
Tom de pele médio claro (Fitzpatrick tipo 3) (U 1F3FC)
Tom de pele médio (Fitzpatrick tipo 4) (U 1F3FD)
Tom de pele médio-escuro (Fitzpatrick tipo 5) (U 1F3FE)
Tom de pele escuro (Fitzpatrick tipo 6) (U 1F3FF)

Então, por exemplo, como todos os emojis humanos, o emoji de bebê? (U 1F476), quando não seguido por um modificador de pele, aparece em uma cor amarela neutra. Por outro lado, quando um modificador de cor da pele o segue, ele muda de acordo.
? U 1F476
?? U 1F476 U 1F3FF
?? U 1F476 U 1F3FE
?? U 1F476 U 1F3FD
?? U 1F476 U 1F3FC
?? U 1F476 U 1F3FB

Unindo emojis

A decisão mais estranha, mas fofa do padrão Emoji/Unicode é que alguns emojis foram definidos juntando-se outros usando o Zero Width Joiner sem um ponto de código independente.

Então, por exemplo, quando combinamos:
Bandeira Branca ?️ (U 1F3F3 U FE0F)
Marceneiro de largura zero (U 200D)
Arco-íris ? (U 1F308)

Aparece como Rainbow Flag ?️‍? (U 1F3F3 U FE0F U 200D U 1F308)

Ou, ?? ? => ??‍?
Ou mesmo, ?? ❤️ ? ?? => ??‍❤️‍?‍??

É como apertar emojis e então, puf?, um novo emoji aparece. Quão fofo é isso?


Eu queria criar uma tabela Markdown com todos os emojis, e as tabelas de sequência de emojis Unicode são a fonte da verdade para isso.

https://unicode.org/Public/emoji/16.0/emoji-sequences.txt
https://unicode.org/Public/emoji/16.0/emoji-zwj-sequences.txt

Então criei um analisador Golang (aqui) que busca e analisa esses arquivos de sequência, gera cada emoji quando um intervalo é descrito no arquivo de sequência e imprime uma tabela de markdown com algumas informações internas para cada um (como o partes caso tenha unido, ou o base tom de pele, etc.).

Você pode encontrar a tabela de descontos aqui.

A última coluna desta tabela está neste formato :.

Golang, Unicode e Rune


str := "⌚"
len([]rune(str)) // 1
len([]byte(str)) // 3


Como discutimos, a codificação de string interna do Golang é UTF-8, o que significa que, por exemplo, para emoji de relógio ⌚ o comprimento de byte é 3 (porque o UTF-8 produz 3 bytes para "escrever" este ponto de código), e o comprimento do ponto de código é 1.

Runa Golang == Ponto de código Unicode

Mas no caso de emojis unidos -mesmo que "apareça" como um- temos muitos pontos de código (runas) e ainda mais bytes.


str := "??‍❤️‍?‍??"
len([]rune(str)) // 10
len([]byte(str)) // 35


E a razão é que:


??‍❤️‍?‍?? : ??   ZWJ   ❤️   ZWJ   ?   ZWJ   ??

??  : 1F469 1F3FC // ?   skin tone modifier [2 code points]
ZWJ : 200D // [1 code points] * 3
❤️  : 2764 FE0F // ❤   VS16 for emoji-style [2 code points]
?  : 1F48B // [1 code point]
??  : 1F468 1F3FE // ?   skin tone modifier [2 code points]


?


Vale ressaltar que a forma como vemos os emojis depende da fonte do nosso sistema e de quais versões de emoji essa fonte suporta.

Não sei exatamente os detalhes internos da renderização de fontes e como ela pode renderizar as fontes unidas corretamente. Talvez seja um post futuro.

Até então, felicidades?

Declaração de lançamento Este artigo é reimpresso em: https://dev.to/moukoublen/unicode-emojis-and-bit-of-golang-3ced?1 Se houver alguma violação, entre em contato com [email protected] para excluí-lo.
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3