最近、Fedora Linux インストールで OS UI とブラウザに絵文字が表示されるという問題が発生しました。この問題により、フォント構成プロジェクトについて少し調査することになりましたが、構成とフォントをテストするには、すべての Unicode バージョンから絵文字を生成する必要があり、最終的にはすべての絵文字と一部の絵文字を印刷する Golang の「スクリプト」を作成することになりました。彼らの内部に関する情報。
この旅行を通じて、私は絵文字の内部、そのバイナリ表現、そして絵文字に関して Unicode 標準によって行われたいくつかの奇妙でかわいい決定について深く掘り下げました。
しかし、最初に、少し戻って用語集を要約しましょう。
エンコーディングは、言語の文字とその文字のバイナリ表現の間の「マッピング」または「翻訳」と説明できます。たとえば、従来の ASCII エンコードでは、文字 a が 0x61 16 進数 (0b01100001 バイナリ) にマップされます。エンコーディングの例としては、Microsoft (Windows 125x) または ISO (ISO/IEC 8859) 8 ビット コード ページがあります。
これらの固定 8 ビット コード ページでは、使用される情報の最小「量」は 8 ビット (1 バイト) です。つまり、256 個の異なる文字を含めることができます。多くの言語をサポートするために、256 のバイナリ コードを再利用してさまざまなコード ページが作成されました。したがって、これらの 3 バイト [0xD0、0xE5、0xF2] が書き込まれたテキスト ファイルは、ギリシャ語 ISO 8859-7 を使用すると「Πες」、西側 ISO 8859-7 を使用すると「Ðåò」として読み取られます (同じバイトですが、解釈が異なります)。コードページに基づく).
ある時点で、テクノロジーの進歩に応じて、多くの異なるコード ページを使用することはうまく拡張できなくなりました。そのため、すべての言語 (およびそれ以上) に適合し、システム間で統一できるものが必要でした。
[多くの歴史と基準を無視して早送りして現在まで]
Unicode 標準は、デジタル化できる世界中のすべての書記体系をサポートするように設計されました。したがって、上記の例を使用すると、Unicode 標準では、ギリシャ文字「Π」のコードは 0x03A0 ですが、ラテン大文字の eth「Ð」のコードは 0x00D0 となり、衝突することはなくなりました。 Unicode Standard にはバージョンがあり、この記事の執筆時点での最新バージョンは 16.0 (仕様) です。
でもちょっと待ってください、この「コード ポイント」とは何ですか?
Unicode 標準では、すべての「文字」、制御文字、絵文字、および一般にすべての定義された項目には、「コード ポイント」と呼ばれる固有のバイナリ値があります。この規格ではすべてのコード ポイントが定義されており、各コード ポイントには純粋なコード/バイナリ情報が含まれています。各コード ポイントの 16 進形式は通常、U 接頭辞を付けて記述されます。たとえば、ギリシャ語の小文字オメガ (ω) コード ポイントは U 03C9.
です。では、これらのコードポイントを実際にエンコードするのは誰でしょうか?
コード ポイントをバイトにエンコードする最初の部分は、エンコード フォームです。標準によると:
エンコーディング形式は、Unicode 文字の各整数 (コード ポイント) を 1 つ以上のコード単位のシーケンスとして表現する方法を指定します。
エンコーディング フォームでは、特定のエンコーディング内の Unicode コード ポイントを表すために使用されるデータの最小単位を指すために「コード ユニット」という用語が使用されます。
Unicode 標準では 3 つの異なるエンコーディング形式が定義されています:
これは、使用されるエンコード形式に応じて、単一のコード ポイントまたは一連のコード ポイントが異なる方法でエンコードされる可能性があることを意味します。
Unicode で実際のバイナリ シリアル化を処理する層はエンコーディング スキームと呼ばれ、すべての低レベルの詳細 (エンディアンなど) を処理します。 Unicode 仕様の表 2-4:
|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 |
注: ほとんどすべての最新のプログラミング言語、OS、およびファイルシステムは、ネイティブ エンコーディングとして Unicode (そのエンコーディング スキームの 1 つ) を使用します。 Java と .NET は UTF-16 を使用しますが、Golang は内部文字列エンコーディングとして UTF-8 を使用します (つまり、メモリ内に文字列を作成すると、前述のエンコーディング形式で Unicode でエンコードされます)
Unicode 標準では、絵文字 (多くの絵文字) のコード ポイントも定義されており、(バージョン番号と多少の混乱はあったものの) 絵文字「標準」のバージョンは Unicode 標準と並行して進歩しています。この記事の執筆時点では、絵文字は「16.0」、Unicode 標準は「16.0」です。
例:
⛄ 雪のない雪だるま (U 26C4)
?微笑んだ目と 3 つのハートを持つ笑顔 (U 1F970)
Unicode は、バリエーションや肌の色など、絵文字のベース コード ポイントに従う修飾子を定義します (バリエーション部分については説明しません)。
EMOJI MODIFIER FITZPATRICK TYPE-X (x は 1 ~ 6) と呼ばれる 6 つの肌のトーン モディファイア (フィッツパトリック スケールに従う) があり、すべての人間の絵文字に影響します。
明るい肌色 (フィッツパトリック タイプ-1-2) (U 1F3FB)
ミディアムライトスキントーン (フィッツパトリックタイプ-3) (U 1F3FC)
ミディアムスキントーン (フィッツパトリックタイプ-4) (U 1F3FD)
中暗めの肌色 (フィッツパトリック タイプ-5) (U 1F3FE)
ダークスキントーン (フィッツパトリック Type-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
絵文字/Unicode 標準の最も奇妙な、しかしかわいい決定は、一部の絵文字が、スタンドアロン コード ポイントを使用せずにゼロ幅結合子を使用して他の絵文字を結合することによって定義されているということです。
たとえば、次のように組み合わせると:
白旗 ?️ (U 1F3F3 U FE0F)
ゼロ幅ジョイナー (U 200D)
虹? (U 1F308)
レインボーフラッグとして表示されます ?️? (U 1F3F3 U FE0F U 200D U 1F308)
または、 ?? ? => ???
あるいは、?? ❤️ ? ?? => ??❤️???
絵文字をまとめて圧縮すると、新しい絵文字が表示されるようなものです。かわいいですね?
すべての絵文字を含むマークダウン テーブルを作成したかったのですが、Unicode 絵文字シーケンス テーブルがそのための真実のソースです。
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 です。
Golang ルーン == Unicode コード ポイント
しかし、結合された絵文字の場合、それが 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