Heim  >  Artikel  >  Backend-Entwicklung  >  Unicode, Emojis und ein bisschen Golang

Unicode, Emojis und ein bisschen Golang

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-10-05 06:10:02179Durchsuche

Unicode, Emojis, and a bit of Golang

In letzter Zeit hatte ich ein Problem mit der Anzeige von Emojis in der Benutzeroberfläche des Betriebssystems und in den Browsern meiner Fedora-Linux-Installation. Dieses Problem veranlasste mich, mich ein wenig mit dem Schriftartenkonfigurationsprojekt zu befassen, aber um meine Konfigurationen und Schriftarten zu testen, musste ich Emojis aus allen Unicode-Versionen erstellen, was mich schließlich dazu veranlasste, ein Golang-„Skript“ zu schreiben, um alle Emojis und einige davon zu drucken Informationen über ihr Inneres.

Während dieser Reise habe ich mich eingehend mit dem Inneren von Emojis, ihren binären Darstellungen und einigen der seltsamen/süßen Entscheidungen befasst, die der Unicode-Standard in Bezug auf Emojis getroffen hat.

Aber zuerst gehen wir einen kurzen Schritt zurück und fassen ein Glossar zusammen.

Kodierung (oder Zeichenkodierung)

Wir könnten Codierung als die „Zuordnung“ oder „Übersetzung“ zwischen einem Buchstaben einer Sprache und der binären Darstellung dieses Buchstabens beschreiben. Beispielsweise ordnet die herkömmliche ASCII-Kodierung den Buchstaben a der Hexadezimalzahl 0x61 zu (binär 0b01100001). Beispiele für Kodierungen sind die 8-Bit-Codepages von Microsoft (Windows 125x) oder ISO (ISO/IEC 8859).

In diesen festen 8-Bit-Codepages beträgt die minimale „Menge“ der verwendeten Informationen 8 Bit (1 Byte), was bedeutet, dass sie 256 verschiedene Buchstaben/Zeichen enthalten können. Durch die Wiederverwendung der 256 Binärcodes wurden verschiedene Codepages erstellt, um viele Sprachen zu unterstützen. Wenn also eine Textdatei mit diesen 3 Bytes geschrieben ist [0xD0, 0xE5, 0xF2], liest man sich bei Verwendung der griechischen ISO 8859-7 als „Πες“ oder bei Verwendung der westlichen ISO 8859-7 als „Ðåò“ (gleiche Bytes, unterschiedlich interpretiert). basierend auf der Codepage).

Irgendwann ließen sich viele verschiedene Codepages mit fortschreitender Technologie nicht mehr gut skalieren. Wir brauchten also etwas, das für alle Sprachen (und mehr) geeignet und systemübergreifend einheitlich ist.

[schneller Vorlauf, wobei viel Geschichte und Standards weggelassen werden, bis zur Gegenwart]

Unicode-Standard

Der Unicode-Standard wurde entwickelt, um alle Schriftsysteme der Welt zu unterstützen, die digitalisiert werden können. Im obigen Beispiel hat also in den Unicode-Standards der griechische Buchstabe „Π“ den Code 0x03A0, während der lateinische Großbuchstabe eth „Г den Code 0x00D0 hat und nicht mehr kollidiert. Unicode Standard verfügt über Versionen, und zum Zeitpunkt des Verfassens dieses Artikels ist die neueste Version 16.0 (Spezifikation).

Aber Moment mal, was ist das für ein „Codepunkt“?

Unicode-Codepunkte

Im Unicode-Standard hat jeder „Buchstabe“, jedes Steuerzeichen, jedes Emoji und jedes definierte Element im Allgemeinen einen eindeutigen Binärwert, der als „Codepunkt“ bezeichnet wird. Der Standard definiert alle Codepunkte und jeder Codepunkt enthält reine Code-/Binärinformationen. Das Hexadezimalformat für jeden Codepunkt wird normalerweise mit einem U-Präfix geschrieben. Der Codepunkt für den griechischen Kleinbuchstaben Omega (ω) lautet beispielsweise U 03C9.

Wer kodieren diese Codepunkte eigentlich?

Unicode-Kodierungsformulare und Kodierungsschemata

Der erste Teil der Kodierung von Codepunkten in Bytes ist die Kodierung von Formularen. Laut Norm:

Codierungsformen geben an, wie jede Ganzzahl (Codepunkt) für ein Unicode-Zeichen als Folge einer oder mehrerer Codeeinheiten ausgedrückt werden soll.

Kodierungsformulare verwenden den Begriff „Codeeinheit“, um sich auf die kleinste Dateneinheit zu beziehen, die zur Darstellung eines Unicode-Codepunkts innerhalb einer bestimmten Kodierung verwendet wird.

Der Unicode-Standard definiert drei verschiedene Kodierungsformen:

  • UTF-32. Codeeinheit mit fester Länge pro Codepunkt. Größe pro Codepunkt: eine 32-Bit-Codeeinheit (4 Bytes).
  • UTF-16. Codeeinheiten variabler Länge pro Codepunkt. Größe pro Codepunkt: eine oder zwei 16-Bit-Codeeinheiten (2–4 Bytes).
  • UTF-8. Codeeinheiten variabler Länge pro Codepunkt. Größe pro Codepunkt: ein bis vier 8-Bit-Codeeinheiten (1~4 Bytes).

Das bedeutet, dass ein einzelner Codepunkt oder eine Folge von Codepunkten je nach verwendeter Codierungsform unterschiedlich codiert werden kann.

Die Ebene, die sich um die eigentliche binäre Serialisierung in Unicode kümmert, heißt Encoding Schemes und kümmert sich um alle Details auf niedriger Ebene (z. B. Endianness). Tabelle 2-4 der Unicode-Spezifikation:


|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           |


Hinweis: Fast alle modernen Programmiersprachen, Betriebssysteme und Dateisysteme verwenden Unicode (mit einem seiner Kodierungsschemata) als native Kodierung. Java und .NET verwenden UTF-16, während Golang UTF-8 als interne String-Kodierung verwendet (das heißt, wenn wir eine beliebige Zeichenfolge im Speicher erstellen, wird sie in Unicode mit der genannten Kodierungsform kodiert)

Emoji

Der Unicode-Standard definiert auch Codepunkte für Emojis (viele davon) und (nach einigen Verwechslungen mit der Versionsnummer) schreitet die Version des Emoji-„Standards“ parallel zum Unicode-Standard voran. Zum Zeitpunkt des Schreibens haben wir Emoji „16.0“ und Unicode Standard „16.0“.

Beispiele:
⛄ Schneemann ohne Schnee (U 26C4)
? Lächelndes Gesicht mit lächelnden Augen und drei Herzen (U 1F970)

Emoji Modifiers and Join

Unicode defines modifiers that could follow an emoji's base code point, such as variation and skin tone (we will not explore the variation part).

We have six skin tone modifiers (following the Fitzpatrick scale) called EMOJI MODIFIER FITZPATRICK TYPE-X (where x is 1 to 6), and they affect all human emojis.

Light Skin Tone (Fitzpatrick Type-1-2) (U+1F3FB)
Medium-Light Skin Tone (Fitzpatrick Type-3) (U+1F3FC)
Medium Skin Tone (Fitzpatrick Type-4) (U+1F3FD)
Medium-Dark Skin Tone (Fitzpatrick Type-5) (U+1F3FE)
Dark Skin Tone (Fitzpatrick Type-6) (U+1F3FF)

So, for example, like all human emojis, the baby emoji ? (U+1F476), when not followed by a skin modifier, appears in a neutral yellow color. In contrast, when a skin color modifier follows it, it changes accordingly.
? U+1F476
?? U+1F476 U+1F3FF
?? U+1F476 U+1F3FE
?? U+1F476 U+1F3FD
?? U+1F476 U+1F3FC
?? U+1F476 U+1F3FB

Joining emojis together

The most strange but cute decision of the Emoji/Unicode Standard is that some emojis have been defined by joining others together using the Zero Width Joiner without a standalone code point.

So, for example, when we combine:
White Flag ?️ (U+1F3F3 U+FE0F) +
Zero Width Joiner (U+200D) +
Rainbow ? (U+1F308)

It appears as Rainbow Flag ?️‍? (U+1F3F3 U+FE0F U+200D U+1F308)

Or, ?? + ? => ??‍?
Or even, ?? + ❤️ + ? + ?? => ??‍❤️‍?‍??

It's like squeezing emojis together, and then, poof ?, a new emoji appears. How cute is that?


I wanted to create a Markdown table with all emojis, and the Unicode emoji sequence tables are the source of truth for that.

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

So I created a Golang parser (here) that fetches and parses those sequence files, generates each emoji when a range is described in the sequence file, and prints a markdown table with some internal information for each one (like the parts in case it joined, or the base + skin tone, etc.).

You can find the markdown table here.

The last column of this table is in this format :.

Golang, Unicode and Rune


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


As we discussed, Golang internal string encoding is UTF-8, which means that, for example, for clock emoji ⌚ the byte length is 3 (because the UTF-8 produces 3 bytes to "write" this code point), and the code point length is 1.

Golang rune == Unicode Code Point

But in the case of joined emoji -even if it "appears" as one- we have many code points (runes) and even more bytes.


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


And the reason is that:


??‍❤️‍?‍?? : ?? + 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]


?


It is worth mentioning that how we see emojis depends on our system font and which versions of emoji this font supports.

I don't know the exact internals of font rendering and how it can render the joined fonts correctly. Perhaps it will be a future post.

Til then, cheers ?

Das obige ist der detaillierte Inhalt vonUnicode, Emojis und ein bisschen Golang. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn