Rumah > Artikel > pembangunan bahagian belakang > Unicode, Emoji dan sedikit Golang
Kebelakangan ini, saya menghadapi masalah dengan pemasangan Fedora Linux saya yang memaparkan emoji dalam UI OS dan penyemak imbas. Isu ini membawa saya untuk menyiasat sedikit tentang projek konfigurasi fon, tetapi untuk menguji konfigurasi dan fon saya, saya perlu menghasilkan emoji daripada semua versi Unicode, yang akhirnya membawa saya menulis "skrip" Golang untuk mencetak semua emoji dan beberapa maklumat tentang dalaman mereka.
Sepanjang perjalanan ini, saya mendalami bahagian dalaman emoji, perwakilan binarinya dan beberapa keputusan pelik/comel yang dibuat oleh Unicode Standard berkenaan emoji.
Tetapi pertama, mari kita berundur dengan cepat dan meringkaskan beberapa glosari.
Kami boleh menerangkan pengekodan sebagai "pemetaan" atau "terjemahan" antara huruf sesuatu bahasa dan perwakilan binari surat ini. Contohnya, pengekodan ASCII tradisional memetakan huruf a kepada 0x61 hex (0b01100001 binari). Contoh pengekodan ialah halaman kod 8-bit Microsoft (Windows 125x) atau ISO (ISO/IEC 8859).
Dalam halaman kod tetap 8-bit ini, "jumlah" minimum maklumat yang digunakan ialah 8-bit (1 bait), yang bermaksud ia boleh mengandungi 256 huruf/aksara yang berbeza. Halaman kod yang berbeza telah dicipta dengan menggunakan semula 256 kod binari untuk menyokong banyak bahasa. Jadi, mempunyai fail teks dengan 3 bait ini ditulis di atasnya [0xD0, 0xE5, 0xF2] dibaca sebagai "Πες" menggunakan ISO 8859-7 Yunani, atau "Ðåò" menggunakan ISO barat 8859-7 (bait yang sama, ditafsir secara berbeza berdasarkan halaman kod).
Pada satu ketika, mempunyai banyak halaman kod yang berbeza tidak berskala dengan baik semasa teknologi berkembang. Jadi, kami memerlukan sesuatu yang boleh memuatkan semua bahasa (dan banyak lagi) dan disatukan merentas sistem.
[ ke hadapan pantas, meninggalkan banyak sejarah dan piawaian, sehingga kini ]
Piawaian Unicode direka untuk menyokong semua sistem penulisan dunia yang boleh didigitalkan. Jadi, menggunakan contoh di atas, dalam piawaian Unicode, huruf Yunani "Π" mempunyai kod 0x03A0 manakala huruf besar Latin eth "Ð" mempunyai kod 0x00D0 dan tidak lagi bertembung. Unicode Standard mempunyai versi, dan pada masa penulisan, versi terkini ialah 16.0 (spesifikasi).
Tetapi tunggu sebentar, apakah "titik kod" ini?
Dalam Unicode Standard, setiap "huruf", watak kawalan, emoji dan setiap item yang ditentukan secara umum mempunyai nilai binari unik yang dipanggil "titik kod". Piawaian mentakrifkan semua titik kod, dan setiap titik kod mengandungi maklumat kod/perduaan tulen. Format heksadesimal untuk setiap titik kod biasanya ditulis dengan awalan U. Contohnya, titik kod Greek Small Letter Omega (ω) ialah U 03C9.
Jadi, siapa sebenarnya kita mengekod titik kod tersebut?
Bahagian pertama pengekodan Mata Kod ke dalam bait ialah Borang Pengekodan. Mengikut standard:
borang pengekodan menentukan cara setiap integer (titik kod) untuk aksara Unikod dinyatakan sebagai urutan satu atau lebih unit kod.
Borang Pengekodan menggunakan istilah "unit kod" untuk merujuk kepada unit data terkecil yang digunakan untuk mewakili titik kod Unikod dalam pengekodan tertentu.
Piawaian Unicode mentakrifkan tiga Borang Pengekodan berbeza:
Ini bermakna satu titik kod atau jujukan titik kod mungkin dikodkan secara berbeza bergantung pada borang pengekodan yang digunakan.
Lapisan yang menjaga siri binari sebenar dalam Unicode dipanggil Skim Pengekodan dan menjaga semua butiran peringkat rendah (seperti endian). Jadual 2-4 Spesifikasi Unikod:
|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: Hampir semua bahasa pengaturcaraan moden, os dan sistem fail menggunakan Unicode (dengan salah satu skema pengekodannya) sebagai pengekodan aslinya. Java dan .NET menggunakan UTF-16, manakala Golang menggunakan UTF-8 sebagai pengekodan rentetan dalaman (ini bermakna apabila kita mencipta sebarang rentetan dalam memori, ia dikodkan dalam Unicode dengan bentuk pengekodan yang disebutkan)
Piawaian Unicode juga mentakrifkan titik kod untuk emoji (banyak daripadanya), dan (selepas beberapa campur dengan nombor versi), versi "standard" Emoji berjalan selari dengan Standard Unicode. Pada masa penulisan, kami mempunyai Emoji "16.0" dan Unicode Standard "16.0".
Contoh:
⛄ Manusia Salji Tanpa Salji (U 26C4)
? Wajah Tersenyum dengan Mata Tersenyum dan Tiga Hati (U 1F970)
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
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
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 ?
Atas ialah kandungan terperinci Unicode, Emoji dan sedikit Golang. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!