UTF-8エンコードの文字数は"8","9","A","B"を除いて数えろ

きっと専門予備校では常識になっていると思いますが、
ざっとググっても出なかったので。

良く出てくるこの手の問題:

16進数表示された、次のUTF-8エンコード結果は、何文字のUnicode文字列をエンコードしたものか。
CF 80 E3 81 AF E7 B4 84 33 2E 31 34 E3 81 A7 E3 81 99
(応用情報・平成24年春季の概要)

10秒で正答へたどり着く技が、タイトルの通りです。

数え方

①各バイトデータの先頭が"8","9","A","B"で始まるものを消す。
CF 80 E3 81 AF E7 B4 84 33 2E 31 34 E3 81 A7 E3 81 99

②残ったバイト数を数える。

すると、残ったものは9バイトあるので、9文字が答えになります。

解説

UTF-8は、Unicodeを8ビット単位で符号化するためのフォーマットです。
元々、ASCIIの規格で表せなかった世界各国の文字を表そうとしたのがUnicodeですが、

  • ASCIIが7ビットで表現されるのに対し、Unicodeは16ビットで表現される
  • 互換性がない

という問題がありました。

これを解決させたのがUTF-8で、

  • ASCIIにある文字は、ASCIIと同じように表し、先頭の1ビットは0とする。
  • ASCIIにない文字は、6ビットごとに分割し、各6ビットごとの塊について、
    • 最初の塊:11から始まるビット*1
    • 2つ目以降の塊:10から始まるビットとする。

というルールでエンコードされます。

ところで、16進数と2進数の関係は

16進数 2進数 16進数 2進数
0 0000 8 1000
1 0001 9 1001
2 0010 A 1010
3 0011 B 1011
4 0100 C 1100
5 0101 D 1101
6 0110 E 1110
7 0111 F 1111

となっていますから、UTF-8エンコードルールと照らし合わせると、

16進数 2進数 UTF-8 16進数 2進数 UTF-8
0 0000 ASCII文字 8 1000 非ASCII文字(2つ目以降)
1 0001 ASCII文字 9 1001 非ASCII文字(2つ目以降)
2 0010 ASCII文字 A 1010 非ASCII文字(2つ目以降)
3 0011 ASCII文字 B 1011 非ASCII文字(2つ目以降)
4 0100 ASCII文字 C 1100 非ASCII文字(先頭)
5 0101 ASCII文字 D 1101 非ASCII文字(先頭)
6 0110 ASCII文字 E 1110 非ASCII文字(先頭)
7 0111 ASCII文字 F 1111 非ASCII文字(先頭)

となります。

UTF-8の文字には、ASCII文字、非ASCII文字(先頭)、非ASCII文字(2つ目以降)の3種類しかなく、
Unicodeの文字数=ASCII文字の数+非ASCII文字の数
であり、また、
非ASCII文字の数=非ASCII文字の先頭の数
であるわけですから、
Unicodeの文字数=UTF-8の文字数−非ASCII文字(2つ目以降)
で答えが求まります。

余談

ちなみに、平成24年春季の応用情報で出たこのUTF-8のデータですが、
デコードすると、「πは約3.14です」となります。
確かに9文字ですね。

*1:UTF-8の規格の範囲では、エンコード対象のUnicodeは6で割ると余りが出る。この余りの部分の長さに応じて、110, 1110, 11110, 111110などを充てる。