このブログは、FacebookやTwitterへのボタンを配備するために、zenbackのサービスを使っている。
zenbackを使うと面白いのが、記事の題名や内容から類推して、他の人がポストした似たような記事を引っ張ってリスト化してくれることだ。
先週の月曜日、「Unicodeを使うと犯罪ですか」というブログを書くと、「似たような記事」リストの中に、「UnicodeとUTF-8の違い」という記事があった。
これもコンピューターを商売にしてるこっちにしたら、なかなかインパクトのある言葉である。
でも、専門外の人が知らないのはしょうがないと思う。
ぼくもよく知らない分野について相当トンチンカンな事を言っていると思われる。
お互い様だ。

ていうか、この間違いは「あるある」であって、相当なプロもUnicode黎明期には勘違いしていた。
ぼくはある日、当時いた会社で、HTMLファイルを大量に納品した。
すると、お客さんから怒り口調で電話が掛かってきて、「フカザワさんUnicodeじゃなくてUTF-8にしてくださいって言ったじゃないですか! すぐに再納品してください!!」と言われた。

これはWindows系の人にありがちな用語法で、Windowsのメモ帳で文字コードを指定して保存しようとすると「ANSI、Unicode、Unicode(Big Endian)、UTF-8のどれにしますか」と言われるのである。

20140113UTF-8

OSに備え付けのプログラムが表示する用語だから、信用して当たり前だ。
しかしながら、この選択肢はいささか、かなり、相当ヘンであると思う。

文字コードとは何か

以下は先週書いた「Unicodeを使うと犯罪ですか」のおさらいである。
 ・コンピューターには音声、画像などの情報がすべて数字になって入っている。この数字をコード(code 符号)と言う。
 ・文字もコードになっている。これを文字コードという。
 ・どの文字をどの数字に対応させるかはいくつか種類がある。

文字と数字の対応を文字コード系(character encoding system)と言うが、前回は以下のようなものを紹介した。

 ・ASCII
  *英数字(A〜Z、a〜z、0〜9)と一部の記号(!@#$%など)が入っている
  *8ビットのうち7ビットだけを使う
  *コードの範囲は0x00〜0x7F
  *Aは0x41、aは0x61、「 」(空白)は0x20、!(感嘆符)は0x21

ASCII - Wikipedia

 ・ISO 8859-1
  *ASCIIの英数字に加えて、フランス語のアクサンのついたアルファベットなどのヨーロッパ特殊文字(À、0xC0など)、著作権記号(©、0xA9)のような記号が入っている
  *8ビットをフルで使う
  *コードの範囲は0x00〜0xFF

ISO/IEC 8859-1 - Wikipedia

 ・JIS X 0201
  *ASCIIの英数字に加えて、アイウエオのようないわゆる半角カナが入っている
  *8ビットをフルで使う
  *コードの範囲は0x00〜0xFF
  *ISO 8859-1でÀが入っている0xC0にはタ、©が入っている0xA9にはゥ(トゥースなどの小書きのウ)が入っている

JIS X 0201 - Wikipedia

 ・ISO 8859-1とJIS X 0201は同時に使えない。著作権の©がゥなどに化けているのは、何らかのミスでISO 8859-1で書かれたサイトをJIS X 0201で読んでいるから

で、Unicodeについて以下のように説明した。
これは、このブログ記事が、日本の字も、ヨーロッパの字も、全部包含する巨大な文字コード、Unicodeによって書かれているからだ。
つまり、ぼくはこのブログ記事を書くために、Unicodeを使っている。
もしUnicodeが犯罪だったら、ぼくはこの寒空に警察に逮捕されることになるが、そういう心配は一切ない。
Unicodeを使うのは犯罪ではないのである。
(中略)
Unicodeには、欧米、アジア、中東、アフリカなど、世界中の文字が入っている。

つまり、UnicodeはASCII、ISO 8859-1、JIS X 0201と同格の文字コード系として紹介している。
これは、ちょっと、だいぶ端折った、不正確な説明であるので、補足する。

Unicodeとは何か

Unicodeは、世界中の文字を一括して登録することを目標にした文字コード系である。

この文字コード系(character encoding system)という言葉には、符号化文字集合(coded character set)と、文字符号化方式(character encoding scheme)という言葉という2つの意味がある。
符号化文字集合というのは、いろいろな文字を集めて番号を振って管理したものである。
文字符号化方式というのは、集められた文字を、コンピューターで使うときにどのような番号を振るか管理してあるものである。
この時点でわけがわからなくなった人ももう少しお付き合いください。

上に上げたASCII、ISO 8859-1、JIS X 0201の場合は、符号化文字集合でもあり、文字符号化方式でもある。
昔のコンピューターはこの2つに厳密な違いがなかった。

Unicodeの符号化文字集合

Unicodeの場合、符号化文字集合(UCS、Universal Coded character Set)として、ただひとつの集合が定義されている。
フゴウカモジシュウゴウというのはいかにも言いにくいので、文字セットと呼ぶことにする。
これはUnicodeスカラー値というU+を付けた4桁から6桁の16進数で管理する。

「 」(空白)はU+0020、!(いわゆる半角の感嘆符)はU+0021、A(いわゆる半角の大文字のエー)はU+0041、a(いわゆる半角の小文字のエー)はU+0061である。
U+0000〜U+007FまではASCIIにゼロゼロをつけてさらにU+をつけたものになっている。
Unicodeのコード表は以下のとおり。(PDF)
The Unicode Standard, Version 6.3 - U0000.pdf

À(フランス語のアクサン・グラーヴのついたアー)はU+00C0、©(著作権記号)はU+00A9である。
U+0080〜U+00FFまではISO 8859-1にゼロゼロをつけてさらにU+をつけたものになっている。
なんだかんだいって欧米中心である。
Unicodeのコード表は以下のとおり。(PDF)
The Unicode Standard, Version 6.3 - U0080.pdf

タ(いわゆる半角カタカナのタ)はU+FF80である(JIS X 0201では0xC0であった)。
ゥ(いわゆる半角カタカナの小書きのウ)はU+FF69である(JIS X 0201では0xA9であった)。
このように、JIS X 0201に0xFEC0を足して、先頭にU+を付けたものになっている。
Unicodeのコード表は以下のとおり。(PDF)
The Unicode Standard, Version 6.3 - UFF00.pdf

これらの文字は16進数4桁に収まっている。
16進数が5桁必要な文字のトップバッターはU+10000であるが、これを調べるには以下のページで「Find chart by hex code」というボックスに「10000」と書いて「Go」
を押すと良い。

Code Charts

必要なコード表(PDF)へのリンクが出てくる。
U+10000は以下の文字である。

「仮面ライダークウガ」に出てくるリント文字に似ているが、これは線文字Bと言ってクレタ島で出土した古代ギリシャ人の文字だそうである。
「クレタ人は嘘つきだ」と言われるが、こんな字を使ってウソ文章を書いていたのだろうか。

U+2000Bは「𠀋」という字で、「丈」という字の右上に点がついた字である。
浪速のジョーこと、ボクサーの辰吉丈一郎さんはこの字を使うそうだ。

このようにU+10FFFF(1,114,111文字。約100万字)までが収録できるが、実際に使われているのは2013年9月30日に公開されたUnicode 6.3.0で110,187文字である。
たぶんぼくが生きている間に100万文字が埋まることはないと思われる。

Unicodeの文字符号化方式

さて、Unicodeのただひとつの文字セット、UCSについて縷々述べてきた。
これに対して、Unicodeの文字符号化方式は、たくさんある。
つまり、Unicodeに番号付きで登録されている文字集合を、実際にコンピューターに格納される数字に置き換える方針が、複数あるということだ。
モジフゴウカホウシキというのも言いにくいので、エンコーディング・スキームと呼ぶ。

普通にパソコンで使うのは、UTF-16とUTF-8の2種類だ。
で、UTF-16はビッグ・エンディアンとリトル・エンディアンの2種類がある。

話が長くなったが、Windowsのメモ帳の名前を付けて保存で言うところの文字コードは、
 ・「Unicode」は「UTF-16(リトル・エンディアン)」のこと
 ・「Unicode (Big Endian)」は「UTF-16(ビッグ・エンディアン)」のこと
 ・「UTF-8」はそのまま「UTF-8」のこと
である。

そもそもUTFとはUnicode Transformation Format(Unicode変換形式)の略である。
「UnicodeじゃなくてUTF-8にしてください」というのは本気でわけがわからない。
では個々のエンコーディング・スキームを見ていこう。

UTF-16(ビッグ・エンディアン)

画像は、「(空白)!AaÀ©タゥ𠀋」という文字列を含むテキスト・ファイルをメモ帳で作成し、Unicode(ビッグ・エンディアン)で保存し、同じファイルをxdumpというプログラムでダンプ(16進数表示)したものである。

20140113_UTF16BE

最初に0xFEFFという字があるが、これは「幅ゼロの改行なしの空白」(Zero Width Non Breaking Space、略してZWNBS)という見えない文字である。
なぜ見えない文字なんか入れるかというと、Unicodeのどのエンコーディング・スキームを使っているか読み込むプログラムに伝えるためである。
この用途で使う場合のZWNBSのことをBOM(Byte Order Mark、バイト順マーク)と言う。
BOMは入れてもいいし入れなくてもいい。
BOMがあると都合がいいプログラムが多い、ということだ。
(正確にはBOMを付けないビッグ・エンディアンのUTF-16はUTF-16BEと呼ぶ。)

次に0x0020があるが、これは空白である。
以下感嘆符(!)(0x0021)、A(0x0041)、a(0x0041)、À(0x00C0)、©(0x00A9)、タ(0xFF80)、ゥ(0xFF69)と来て、最後の𠀋が「0xD840 DC0B」と急に4オクテットになっている。

ちなみに、8ビットのことを1バイトといいがちだが、これはパソコンのCPUが8ビットだったころの名残りで、Unicodeの用語としては8ビットを1オクテットと言う。
いろいろ覚えなきゃいけなくて面倒だね。

UTF-16(ビッグ・エンディアン)は、U+FFFFまでのUnicodeスカラー値はそのままの16進数16ビットになる。
ところが、U+10000以降の文字は、16進数32ビット、つまり16ビット文字2つになる。
これが世に言うサロゲート・ペアだ。

サロゲート・ペアについては、このブログでも前に書いた。

イジハピ! : 【第322回】文字コード【プチ】研究・サロゲートペア早わかり(1)

ということで、UTF-16(ビッグ・エンディアン)は、16ビット文字1つまたは2つの可変長コード、ということになる。
U+0000からU+FFFFまでは、Unicodeスカラー値とUTF-16文字コードが一致するので、文字セット(符号化文字集合)とエンコーディング・スキーム(文字符号化方式)の区別をせずにすむ。
しかしU+10000を超えると、サロゲート・ペアを使うので、Unicodeスカラー値とUTF-16文字コードがかけ離れた値になる。

サロゲート・ペアはサポートしているアプリとしていないアプリがある。
していないアプリでサロゲート・ペアを表示させるとどうなるかは不定である。

UTF-16(リトル・エンディアン)

画像は同じファイルを「Unicode」で保存し、xdumpで見たものである。

20140113_UTF16LE

まず0xFFFEという字が出てくる。
これはZWNBSである。
UTF-16(ビッグ・エンディアン)のZWNBSは0xFEFFであった。
つまり、リトル・エンディアンはビッグ・エンディアンを16ビット単位でひっくり返したものである。
なお、UnicodeではU+FEFFという文字はZWNBSであったが、U+FFFEという文字は絶対に定義されないことになっている。
よって、ファイルの先頭がU+FEFFであればビッグ・エンディアンのUTF-16、U+FFFEであればリトル・エンディアンのUTF-16であると分かる。
これがBOMの機能である。

以下、空白が0x2000、感嘆符(!)が0x2100、大文字のAが0x4100と、すべてUTF-16(ビッグ・エンディアン)を16ビット単位で反転させたものになっている。

UTF-16にビッグ・エンディアンとリトル・エンディアンの2種類がなぜあるかというと、昔パソコンのCPUが16ビットだった頃、インテルとモトローラでチップ内の演算方式が違ったから、データを大量に処理する効率を上げるために2つのフォーマットがあったそうだ。
それぐらいお互い歩み寄って統一しろよ!
と思うが、メーカー間で沽券があるのでなかなかそうも言えない。
この様子が、「ガリヴァー旅行記」に出てくる「ゆで卵を小さい端(little end)から食べるのと大きな端(big end)から食べるのとどっちが食べやすいか」という議論で戦争になった部族になぞらえて、ビッグ・エンディアン、リトル・エンディアンと呼ばれている。
これ、たまにブログを見ていると、「ビッグ・インディアン」、「リトル・インディアン」と間違っているケースが見られるので注意しよう。

UTF-8

最後がUTF-8である。
例によって同じファイルをUTF-8で保存してxdumpでダンプする。

20140113_UTF8

まず、0xEFBBBFというコードが出てくる。
ここまで、24ビット(3オクテット)がBOM(U+FEFF)である。
不穏な出発である。

次に空白が0x20である。

(※2016-10-29補遺 以下の部分に間違いがあり、ご指摘を受けました。修正してお詫びします)

以下感嘆符(!)(0x21)、A(0x41)、a(0x41)、À(0xC0)、©(0xA9)と続く。
つまり、ISO 8859-1の範囲では(ざっくり言うと欧米では)、ISO 8859-1と完全互換の8ビットである。

Unicode以前に作られた、欧米のソフトウェアはそのまま無改造で使えることになる。

一方、タは0xEFBE80、ゥは0xEFBDA9と、半角カナは3オクテットになる。

以下感嘆符(!)(0x21)、A(0x41)、a(0x61)と続く。
つまり、ASCIIの範囲では、ASCIIと完全互換の7ビットである。

Unicode以前に作られた、米国語対応ソフトウェアはそのまま無改造で使えることになる。

一方、Àは0xC380、©は0xC2A9と、ISO-8859-1右面(欧州特殊文字)は2オクテットになり、
タは0xEFBE80、ゥは0xEFBDA9と、半角カナは3オクテットになる。
最後の𠀋は「0xF0A0 809B」と4オクテットである。
このように、UTF-8は1オクテット以上の可変長文字である。
規格上は6オクテットまで存在するが、現在4オクテットまでしか使われていない。

米国は1オクテットなのにカタカナや漢字は3オクテット以上、ということで、文化的差別を感じてしまうこともあるが、現実問題コンピューターで送受信される文字は、プログラムや数字やHTMLのタグなど、ほとんどがASCIIの範囲の英数字であるから、UTF-8を使ったほうが確実に効率は良い。
本の原稿のように大量の日本語を含むものや、固定長である価値が高いファイルについてはUTF-16を使えば良い。
まあ適材適所である。

ANSI

メモ帳の名前を付けて保存の文字コード選択肢には、他に「ANSI」というのがある。

20140113UTF-8

これ、なんだろう。
とりあえずアンシと読むらしい。

the ANSI - pronunciation of the ANSI by Macmillan Dictionary

これは、American National Standards Institute(米国国家規格協会)の略で、日本のJISにあたる国家規格を定める団体である。
では、メモ帳でANSIという選択肢にすると、アメリカ規格のASCIIになるかというと、そうではなく、Unicode以前から日本のパソコンの標準的な文字コードであったShift_JISになる。
(正確にはShift_JISをMicrosoftが拡張したCP932になる。)

たぶんアメリカ版Windowsのメモ帳(notepad)ではASCIIになるのであろう。
でもだったらASCIIにすればいいと思わないか。
これ、1990年代から直らない。

さすがに「Shift_JISにしてください」という意味で「アンシにしてください」というお客さんはまずいないが、「UnicodeにしないでUTF-8にしてください」というお客さんは、いる。
現実にぼくは遭遇した。
遭遇してどうしたかというと、お客様は神様であるから、「あっスイマセーン」と言って適当にUTF-8に変換して再納品した。
「そもそもUTFとはUnicode Transformation Formatの略であって・・・」などと説明するのが、面倒な気持ちもあった。
しかしまあ、プロにしてもこれだけ用語法に齟齬があるのだから、「Unicodeを使うと犯罪ですか」という言葉が、それほど奇ッ怪な発言であるとも思わない。