Navigate back to the homepage

Unicode での、複数符号位置による文字表現

Kenya Hondoh
November 6th, 2021 · 1 min read

最近、矢野啓介著「文字コード技術入門」(技術評論社・2010)を読みました。 その中でも興味深かった Unicode の結合文字について簡単に紹介します。

Unicode における、符号位置の結合による文字表現

Unicode では、複数の文字の羅列を、新たな「1文字」として表現する方法が存在します。。

例えば、か゚ という文字列がそうです。

これは、「か」と半濁音を足し合わせた文字で、符号位置で表現すると下記の通りです。

U+304B + ◌ ゚ U+309A = か゚ U+304B U+309A


ターミナル上で、実際にバイト列を足し合わせて か゚ を表現してみましょう。

符号化方式として UTF-8 を例にすると、バイト列は次のようになります。

か (e3 81 8b) + ◌ ゚ (e3 82 9a) = か゚ (e3 81 8b e3 82 9a)

1# 末尾の 0x0a は LF(改行)
2echo "e3 81 8b e3 82 9a 0a" | xxd -p -r
3か゚

xxd … テキスト → バイナリ変換するコマンド

-r … リバース(バイナリ → テキスト)

-p … 16 進数で入出力

文字の結合で表現可能な絵文字

同じように、絵文字においても、複数の異なる符号位置の足し合わせで新しい符号位置を表現しているものがあります。その一覧は下記のリストから見ることができます。

Unicode Recommended Emoji ZWJ Sequences

例えば以下のようなものです。

😵 + 💫 = 😵‍💫

絵文字の場合は、単に符号を並べるだけでなく ZWJ (Zero Width Joiner U+200D)  という文字を「演算子」として利用します。

これは、Unicode におけるアラビア文字などで、複数の文字列を結合する際に使用する制御文字です。Wikipedia - ゼロ幅接合子

”😵” (U+1F635) + “zwj” + (U+200D) + ”💫” (U+1F4AB)

= 😵‍💫 U+1F635 U+200D U+1F4AB

ここで、UTF-8 のバイト列を使って「演算」してみましょう(?)

1echo "😵" | xxd
200000000: f09f 98b5 0a .....
3
4echo "💫" | xxd
500000000: f09f 92ab 0a .....

↑ の末尾にある LF (0x0a) を抜き、2 つの絵文字の間に ZWJ (U+200D) を間に挟むと次のようなバイト列になります。

😵(f09f98b5) ZWJ(e2808d) 💫(f09f92ab) = 😵‍💫(f09f98b5 e2808d f09f92ab)

1# 末尾の 0a は LF
2echo "f09f98b5 e2808d f09f92ab 0a" | xxd -p -r
3😵‍💫

1 つの絵文字の表現のために 11 byte も必要ですね。

結合文字の問題

Unicode の結合文字がうむトラブルとしては次のようなものがあるようです。

(1)同一の字体が、複数の符号位置を持つ

Unicode では、同じ字体なのに複数の表現方法が可能である文字が存在します。

例えば、「ゔ」を例にすると、以下の 2 通りの表現方法があります。

  • ゔ (U+3094)
  • う + ◌ ゙ (U+3046 U+3099)

見かけ(字体)は同じでも、バイト列でみると確かに異なります。

1echo "ゔ" | xxd
200000000: e381 86e3 8299 0a .......
3
4echo "ゔ" | xxd
500000000: e382 940a ....

こうした文字が混入は、テキスト検索などにおいて意図しない挙動をうむ原因となります。

この問題を避ける一般的な対処として、正規化があります。

ここでは詳しくは書きませんが、例えば、「ゔ」(U+3046 U+3099) を「ゔ」(U+3094) に変換して、1 つの字体に対して 1 つの符号表現しかないように変換を施すようなことをします。

(2)文字数の扱い

結合によって表現された文字を構成する要素もまた Unicode で符号位置を与えられた文字です。 これにより、我々人間には 1 文字にしか見えないものが、複数の文字で構成されるということが起きます。

例えば、絵文字 ”😵‍💫” U+1F635 U+200D U+1F4AB は 3 つの独立した符号位置をもつ文字から構成されるので、3 文字として認識される場合があります。

以下に Python での例を示します。

1▶ python3
2Python 3.9.5 (default, May 4 2021, 03:36:27)
3[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
4Type "help", "copyright", "credits" or "license" for more information.
5>>> len("😵‍💫")
63
7>>> "😵‍💫"[0]
8'😵'
9>>> "😵‍💫"[1]
10'\u200d' # = ZWJ の Unicode 符号位置
11>>> "😵‍💫"[2]
12'💫'

まとめ

  • Unicode には、複数の符号位置を足し合わせて表現可能な文字がある
  • 文字数の扱いなどをめぐってプログラミング上問題となることがある

More articles from Kenya Hondoh

草津温泉

徳明園 草津温泉 高崎市立美術館

November 30th, 2020 · 1 min read

読書感想文,『オブジェクト指向UIデザイン』

OOUI は銀の弾丸らしいよ

November 11th, 2020 · 1 min read
© 2020–2023 Kenya Hondoh
Link to $https://twitter.com/EarllibraryLink to $https://github.com/kenchonLink to $https://www.linkedin.com/in/kenya-hondoh-2a7067123/