『𝑩𝑰𝑮 𝑳𝑶𝑽𝑬__』についての考察
この投稿は機種依存文字を含みます。
X(旧・Twitter)で以下の投稿を見て、「このフォントどうやって出すんだ…?」と疑問を抱いたのがきっかけです。
少し前に『𝑩𝑰𝑮 𝑳𝑶𝑽𝑬__』というミーム?が流行ったときにも見かけていたのですが、あらためて気になったので色々調べてみることにしました。
この字体、どうもX独自のフォント設定などによるものではなく、もともとUnicodeに定義されている文字だということが分かりました。
ユニコード名を「MATHEMATICAL BOLD ITALIC CAPITAL」というそうで、本来は学術用・装飾用に定義されているようです。
ちなみにこういうサイトで色々変換できます。
ちなみに 𝑨 の場合はUnicodeコードポイントがU+1D468
となっています。
UTF-8変換したら…
𝑨をUTF-8に変換したらどうなるのだろうと思い、まずUnicodeのエスケープシーケンスを行ったところ、\ud835\udc68
と1文字から2文字?のエスケープシーケンスが得られました。
次にUTF-8にバイトコード変換を行ったところ、0xf0 0x9d 0x91 0xa8
となりました。
0xd835 + 0xdc68 = 0x1b49d
となり、コードポイント0x1d468
と一致しません。またUTF-8のバイトコードの上位2ビット0xf09d
、下位2ビット0x91a8
もエスケープシーケンスとそれぞれ一致しません。
このことに違和感を覚え、それぞれどういう関係性になっていてどのように導出できるのか?が気になって夜しか眠れなくなってしまいました。
Unicodeの追加面とサロゲートペア
ChatGPTに聞いてみたところ、補助平面(=追加面)とサロゲートペアというのがどうやらキーワードになっていそうだ、ということが分かりました。
Unicodeには通常使われる文字のほとんどが含まれる基本多言語面U+0000 ~ U+FFFF
と、それ以外の追加面があるそうです。で、これをUTF-16変換する際にはサロゲートペアにする必要があるということでした。
このことは上記のWikipediaのページにも記載がありますが、文系の私的には以下のサイトが分かりやすかったかなと思います。
Unicodeコードポイント→UTF-8(バイトコード)変換
𝑨のUnicodeコードポイントU+1D468
からUTF-8のバイトコードを算出してみます。
まず、上記のコードポイントを2進数に基数変換します。以下になります。
1 1101 0100 0110 1000
次の変換規則に従い、導出されたビット列を x に割り当てていきます。このとき、桁数が足りない場合は先頭(上位ビット)に 0 を足して割り当てます。
※これの意味が分からなくて調べたりChatGPT先生に聞きまくってたりしました。結局理屈は理解できませんでしたが…
符号位置(16進) | UTF-8のビット列(2進) | |
---|---|---|
範囲1 | U+0000 – U+007F | 0xxx xxxx |
範囲2 | U+0080 – U+07FF | 110x xxxx 10xx xxxx |
範囲3 | U+0800 – U+FFFF | 1110 xxxx 10xx xxxx 10xx xxxx |
範囲4 | U+10000 – U+10FFFF | 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx |
変換テーブルは以下を参照しました。
今回の場合、コードポイントの2進数が17ビットに対して「範囲4」の計21ビットを割り当てますので、先頭に4ビットの 0 を足して左から順に割り当てていきます。
0 0001 1101 0100 0110 1000
割り当てると、以下になります。
1111 0000 1001 1101 1001 0001 1010 1000
これを8ビットずつ16進数に変換すると
1111 0000 = 0xf0
1001 1101 = 0x9d
1001 0001 = 0x91
1010 1000 = 0xa8
となり、UTF-8のバイトコードが求まりました。
Unicodeコードポイント→UTF-16(サロゲートペア)変換
同じく𝑨のUnicodeコードポイントU+1D468
からUTF-16のサロゲートペアを算出してみます。
コードポイントから追加面のオフセットを引きます。
0x1d468 - 0x10000 = 0xd468
これを2進数に基数変換します。
1101 0100 0110 1000
先頭に 0 を足して20ビットにします。
0000 1101 0100 0110 1000
上位10ビットと下位10ビットを分割し、それぞれHSG, LSGとします。
HSG = 00 0011 0101 = 0x0035
LSG = 00 0110 1000 = 0x0068
それぞれに予約アドレスの開始領域を足します。
HSG = 0x0035 + 0xd800 = 0xd835
LSG = 0x0068 + 0xdc00 = 0xdc68
となり、UTF-16のサロゲートペアが求まりました。
まとめ
UTF-8バイトコード→UnicodeコードポイントやUTF-16サロゲートペア→Unicodeコードポイントについては上記と逆の手順で算出できるはずですが、疲れたのでこの辺にしておきます。
普段はあまり気にしないところですが、せっかく気になった機会だったのでちょっと深堀りしてみました。おしまい。