Недавно у меня возникла проблема с моей установкой Fedora Linux, отображающей смайлы в пользовательском интерфейсе ОС и браузерах. Эта проблема заставила меня немного изучить проект конфигурации шрифтов, но для тестирования моих конфигураций и шрифтов мне нужно было создать смайлы из всех версий Unicode, что в конечном итоге привело меня к написанию «скрипта» Golang для печати всех смайлов и некоторых информацию о своих внутренностях.
Во время этой поездки я глубоко погрузился во внутреннюю структуру смайлов, их двоичные представления, а также в некоторые странные/милые решения, принятые стандартом Unicode в отношении смайлов.
Но сначала давайте сделаем небольшой шаг назад и подведем итоги глоссария.
Мы могли бы описать кодирование как «отображение» или «перевод» между буквой языка и двоичным представлением этой буквы. Например, традиционная кодировка ASCII отображает букву a в шестнадцатеричном формате 0x61 (двоичный код 0b01100001). Примерами кодировок являются 8-битные кодовые страницы Microsoft (Windows 125x) или ISO (ISO/IEC 8859).
В этих фиксированных 8-битных кодовых страницах минимальный «объем» используемой информации составляет 8 бит (1 байт), что означает, что они могут содержать 256 различных букв/символов. Различные кодовые страницы были созданы путем повторного использования 256 двоичных кодов для поддержки многих языков. Таким образом, текстовый файл с этими 3 байтами, записанными в нем [0xD0, 0xE5, 0xF2], читается как «Πες» в греческом ISO 8859-7 или «Ðåò» в западном ISO 8859-7 (те же байты, интерпретируемые по-разному). на основе кодовой страницы).
В какой-то момент наличие множества разных кодовых страниц стало плохо масштабироваться по мере развития технологии. Итак, нам нужно было что-то, что подходило бы ко всем языкам (и не только) и было бы унифицировано для всех систем.
[ перенесемся вперед, опустив большую часть истории и стандартов, в настоящее время ]
Стандарт Unicode был разработан для поддержки всех мировых систем письма, которые можно оцифровать. Итак, используя приведенный выше пример, в стандартах Unicode греческая буква «Π» имеет код 0x03A0, а латинская заглавная буква eth «Ð» имеет код 0x00D0 и больше не конфликтует. У стандарта Unicode есть версии, и на момент написания последней версией является 16.0 (спецификация).
Но подождите, что это за «кодовая точка»?
В стандарте Unicode каждая «буква», управляющий символ, смайлик и каждый определенный элемент в целом имеют уникальное двоичное значение, называемое «кодовой точкой». Стандарт определяет все кодовые точки, и каждая кодовая точка содержит чистый код/двоичную информацию. Шестнадцатеричный формат для каждой кодовой точки обычно записывается с префиксом U. Например, кодовая точка греческой строчной буквы Омега (ω) — U 03C9.
Так кто же нам на самом деле кодирует эти кодовые точки?
Первая часть кодирования кодовых точек в байты — это формы кодирования. Согласно стандарту:
формы кодирования определяют, как каждое целое число (кодовая точка) для символа Юникода должно быть выражено как последовательность из одной или нескольких кодовых единиц.
Формы кодирования используют термин «единица кода» для обозначения наименьшей единицы данных, используемой для представления кодовой точки Юникода в конкретной кодировке.
Стандарт Unicode определяет три различные формы кодирования:
Это означает, что одна кодовая точка или последовательность кодовых точек могут быть закодированы по-разному в зависимости от используемой формы кодирования.
Уровень, который отвечает за фактическую двоичную сериализацию в Юникоде, называется схемами кодирования и отвечает за все детали низкого уровня (например, порядок байтов). Таблица 2-4 спецификации 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 |
Примечание. Почти все современные языки программирования, операционные системы и файловые системы используют Unicode (с одной из его схем кодирования) в качестве собственной кодировки. Java и .NET используют UTF-16, тогда как Golang использует UTF-8 в качестве внутренней кодировки строк (это означает, что когда мы создаем любую строку в памяти, она кодируется в Unicode с указанной формой кодировки)
Стандарт Unicode также определяет кодовые точки для смайлов (их много), и (после некоторой путаницы с номером версии) версия «стандарта» Emoji развивается параллельно со стандартом Unicode. На момент написания у нас есть Emoji «16.0» и стандарт Unicode «16.0».
Примеры:
⛄ Снеговик без снега (U 26C4)
? Улыбающееся лицо с улыбающимися глазами и тремя сердцами (U 1F970)
Юникод определяет модификаторы, которые могут следовать за базовым кодом смайлика, например вариацию и оттенок кожи (мы не будем рассматривать вариационную часть).
У нас есть шесть модификаторов тона кожи (по шкале Фицпатрика), которые называются EMOJI MODIFIER FITZPATRICK TYPE-X (где x — от 1 до 6), и они влияют на все человеческие смайлы.
Светлый тон кожи (тип Фитцпатрика-1-2) (U 1F3FB)
Средне-светлый тон кожи (Тип Фитцпатрика-3) (U 1F3FC)
Средний тон кожи (тип Фитцпатрика-4) (U 1F3FD)
Средне-темный тон кожи (тип Фитцпатрика-5) (U 1F3FE)
Темный оттенок кожи (Тип Фитцпатрика-6) (U 1F3FF)
Так, например, как и все человеческие смайлы, детский смайлик ? (U 1F476), если за ним не указан модификатор скина, отображается нейтральным желтым цветом. Напротив, когда за ним следует модификатор цвета кожи, он соответствующим образом меняется.
? U 1F476
?? U 1F476 U 1F3FF
?? U 1F476 U 1F3FE
?? U 1F476 U 1F3FD
?? U 1F476 U 1F3FC
?? U 1F476 U 1F3FB
Самое странное, но симпатичное решение стандарта Emoji/Unicode заключается в том, что некоторые смайлы были определены путем объединения других с помощью Zero Width Joiner без отдельной кодовой точки.
Так, например, когда мы объединяем:
Белый флаг ?️ (U 1F3F3 U FE0F)
Столярный станок нулевой ширины (U 200D)
Радуга? (U 1F308)
Появляется как Радужный флаг ?️? (U 1F3F3 U FE0F U 200D U 1F308)
Или, ?? ? => ???
Или даже, ?? ❤️ ? ?? => ??❤️???
Это похоже на сжатие смайлов вместе, а затем, пуф?, появляется новый смайлик. Насколько это мило?
Я хотел создать таблицу Markdown со всеми смайлами, и таблицы последовательности смайлов в Юникоде являются источником истины для этого.
https://unicode.org/Public/emoji/16.0/emoji-sequences.txt
https://unicode.org/Public/emoji/16.0/emoji-zwj-sequences.txt
Поэтому я создал парсер Golang (здесь), который извлекает и анализирует эти файлы последовательностей, генерирует каждый смайлик, когда диапазон описан в файле последовательности, и печатает таблицу уценки с некоторой внутренней информацией для каждого из них (например, ]части в случае, если они объединены, или базовый тон кожи и т. д.).
Таблицу уценок можно найти здесь.
Последний столбец этой таблицы имеет формат :.
str := "⌚" len([]rune(str)) // 1 len([]byte(str)) // 3
Как мы уже говорили, внутренняя строковая кодировка Golang — UTF-8, что означает, что, например, для смайликов часов ⌚ длина байта равна 3 (поскольку UTF-8 создает 3 байта для «записи» этой кодовой точки), а длина кодовой точки равна 1.
Руна Голанга == Кодовая точка Юникода
Но в случае объединенных эмодзи, даже если они «появляются» как один, у нас есть много кодовых точек (рун) и еще больше байтов.
str := "??❤️???" len([]rune(str)) // 10 len([]byte(str)) // 35
И причина в том, что:
??❤️??? : ?? 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]
?
Стоит отметить, что то, как мы видим смайлы, зависит от нашего системного шрифта и от того, какие версии смайлов поддерживает этот шрифт.
Я не знаю точных внутренних особенностей рендеринга шрифтов и того, как он может правильно отображать объединенные шрифты. Возможно, это будет будущий пост.
До свидания?
Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.
Copyright© 2022 湘ICP备2022001581号-3