2019/04/21 Updated by

Unicode and UTF-8, UTF-16, UTF-32


[Up] Japanese English


Unicode and UTF


Unicode (ISO-10646) は、1980年台に行われた世界の文字をひとつのコード体系で表現しようという 野心的な試みから生れた規格です。 1文字を表現するのに16 bit 幅を使う、32 bit 幅を使う、などいろいろな提案がありましたが、 (当時は) 16 bit に決定されました。


utf-16 と utf-8

現代から見ると 32 bit 幅を使う案の方が優れていたとも考えられるのですが、 それまで1文字を 8bit 幅 で表してきた欧米系の人々にとっては 1文字の幅を 16 bit にしようという提案ですら メモリ効率の観点からなかなか受け入れ難い提案であったと言えます。

すったもんだあって16 bit幅で決着したのですが、 Unicode は16 bit で定義するがそれを交換(transfer)するために使うコードを 工夫すればいいのではないか、という話になります。そうやって出来たのが utf-8 です。

まず、1バイトの上位ビット(MSB)から何番目に初めて0 bitが現れるかで パターンを分けてみましょう。 すると次の表のようになります(xは0または1を表します)。

16 bit のUnicode を表現するには、1〜3 byte sequence の utf-8 でよいことが分ります。

bit pattern 意味 1文字当たりのバイト数 utf-8の1文字を表す bit sequence 表現可能なbit数
0xxx xxxx ASCII と同じ 1 0xxx xxxx 7
10xx xxxx データを運ぶコンテナ - - -
110x xxxx 欧州系の文字 2 110x xxxx 10xx xxxx 11
1110 xxxx アジア系などの文字 3 1110 xxxx 10xx xxxx 10xx xxxx 16
1111 0xxx 拡張されたUnicode 4 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx 21

utf-16 は unicode の16 bit パターンをそのまま使っていました。


16 bit 幅では足りない。拡げよう。

16 bit では、表せる文字に限りがあるので、コードを拡張しようという話がでてきました。 すると、utf-16 ではたまたま 0xD800 〜 0xDFFF というコードが未使用だったので、そこを使って 2つの16bitコード(1文字目は 0xD800 〜 0xDBFF, 2文字目は 0xDC00 〜 0xDFFF) で1文字を表せばいいのではないか、という案がでてきました。 utf-16 で、2つの16 bit 文字を使って1文字を表すことをサロゲート・ペア(代理ペア)と代びます。

文字の位置 16 bit コードの範囲 bit表現
1文字目 0xD800-0xDBFF 1101 10xx xxxx xxxx
2文字目 0xDC00-0xDFFF 1101 11xx xxxx xxxx

サロゲート・ペアを使うと 20 bit表現できます。 しかし、サロベート・ペアの 0000 xxxx xxxx xxxx xxxx というビットパターンを 16bit の Unicode と同一視するのは、同じ文字に対する表現が2通りあることになり無駄です。 そこで、0000 xxxx xxxx xxxx xxxx というビットパターンは 0001 xxxx xxxx xxxx xxx を 表すことにします。すると 1111 xxxx xxxx xxxx xxxx というビットパターンは 1 0000 xxxx xxxx xxxx xxx を 表すことになります。元の16bit空間よりも、空間が 17 倍広くなりました。

Unicodeの 0 0001 xxxx xxxx xxxx xxxx 〜 1 0000 xxxx xxxx xxxx xxxx の範囲を utf-8 で表現するときは、21 bit をそのまま 4バイトのutf-8で表現します。 utf-16 のサロゲート・ペアで表現するときだけは上位5 bit が1小さい数で表現されていましたが、 utf-8やutf-32ではそのような表現は使いません。


utf-32

Unicode が21bit幅になったので、直接表現するために 32bit 幅 (4byte)のutf-32が生まれました。


まとめ

x = 0 or 1, yyyyy = pppp + 1, yyyyy = 00001 〜 10000.

表中で x で表現されている数値の並び順は、他のutf表現になってもそのまま保たれる。 utf-8 では、ある数値に対して表現できる最も短いバイト・シーケンスを使うこと。

Unicode (utf-32) utf-16 utf-8
0000 0000 0000 0000 0000 0000 0xxxx xxxx 0000 0000 0xxx xxxx 0xxx xxxx
0000 0000 0000 0000 0000 0xxx xxxxx xxxx 0000 0xxx xxxx xxxx 110x xxxx 01xx xxxx
0000 0000 0000 0000 xxxx xxxx xxxxx xxxx xxxx xxxx xxxx xxxx 1110 xxxx 01xx xxxx 01xx xxxx
0000 0000 000y yyyy xxxx xxxx xxxxx xxxx 1101 10pp ppxx xxxx 1101 11xx xxxx xxxx 1110 1yyy 10yy xxxx 01xx xxxx 01xx xxxx