Unicodeの憂鬱


40歳目前の中年エンジニアが独りよがりにUnicodeとの思い出を書き綴ってみる。
記憶をベースに細かいことを気にせずに大枠の雰囲気が伝わるように書いてみる。

なぜUnicode?

先日MySQLのバージョンアップを行ったが、その時にCharacter setをutf8からutf8mb4に変換した。
MySQLを普段使わない人はutf8mb4なに?と思うかも知れません。そうです、これはMySQL固有のものです。

どうやらMySQLは永らくUTF8は1文字が1~3バイトであることが前提の実装になっていた。
で、4バイトな文字が登場して、「プギャー」となってutf8mb4というものが生み出されたものと推測される。
その内、utf8mb5が登場するかも知れないなと思うし、そのころにはMySQLはどうなっているんだろうか?と遠い目をしてしまう。

少し気になって調べてみると現在のUnicode9.0(2016/6/21)ではU+10FFFFまでのコードポイントが予約されている。一方4バイト長のUTF8に格納できる最大のコードポイントはU+1FFFFF(21ビット)とのことなので、現時点ではすべてのUnicode文字を4バイト長のUTF8で表現できるみたい。もうしばらく大丈夫そう。

文字コードの混乱期

Unicodeの制定は1993年らしい。インターネット創世記と近い時代に出来ている。
当時の日本は文字コードとしてWindowsであればShift-JIS(MS932)、UNIXであればEUC-JP、IBM系のコンピュータであればEBCDICなどが互いの覇権を競い合う群雄割拠の時代であった。
それぞれ単体で生活している分には問題ないがデータ連携すると簡単に文字化けしたりと、それなりに混沌とした状況であったが、共通していることとして英数字は1バイト、半角カタカナってのがあってそれも1バイト、それ以外の日本語は2バイトというお決まりがあった。

そして半角/全角ってなんだ?ってのがコンピューターの世界に足を踏み入れた人が、初期の段階に受ける洗礼の一つであった。

特にEBCDICなんかは本気で大変で、半角カタカナと英小文字で同じコードが割り当てられていて半角カタカナを使うか、英小文字を使うかどちらか切り替えて使うという画期的なUXを誇っていた。
また全角文字の1バイト目と2バイト目には半角文字と同じコードが平気でアサインされているため単体では全角文字で1文字なのか半角文字で2文字なのかを特定することができずに全角文字と半角文字の切り替わりの位置にシフトコードと呼ばれる謎の1バイトが挿入されていた。

こういった混乱は日本だけにとどまらずにFar Eastな各国でも同様に起こっていたのではなかろうか。
少なくとも同じバイト表現でも違う国では別の文字、ということがすごく当たり前に起こっていたのである。

多くの国々の人たちが文字コードの統一を神に願ったのである。

Unicodeの登場

そんな時代背景の中で、Unicodeが登場した。
Unicodeには世界中のあらゆる文字にユニークな番号を与えるという全人類の夢が込められていた。
その理念はいまも継続できている。しかし人類はここで重大な過ちを犯してしまった。
そしてそのことが今日のUnicode周辺のややこしさの要因となっている。

UCS-2

当時は世界中の文字は65536種類に収まり、全ての文字に2バイトのコードを与えることで問題を解決できると信じられていた。
その発想によって生み出されたのがUCS-2である。当時はUCS-2という単語はあまり耳にした覚えはなく、後付けで命名されたのかもしれない。しかし当時Unicodeといったら全ての文字を2バイトで表現可能なUCS-2で実現されることが多く、Javaをはじめとする各種のプログラミング言語も文字列は内部でUCS-2で保持していた。プログラミング言語においては全ての文字が等しく2バイトであるという世界は処理がシンプルになり都合がよかったのである。

UTF-8

もしあなたが英語圏な人だったら、そして日本語や中国語とは縁もなく世界の共通語である英語だけで十分に生きていけるとするならば、UCS-2についてどのような感情を抱くであろうか?
もともとASCII文字だけで生きてきた人にとっては何のメリットもなくデータ容量が2倍になるという仕打ちを受けるのである。
UTF-8はそんな感情から生まれたエンコーディングである。(たぶん)
UTF-8は英語圏な人々が使用するASCII文字は1バイトで表現できる。ASCII文字だけが含まれる文字列においてはUTF-8エンコーディング前後でのバイト表現は同一となる。
その代わりにこれまで2バイトで表現できていた文字が時には3バイト必要だったりした。
しかし英語圏な人々にとっては普段はなにも不利益を被ることなく、いざとなったら世界中の文字に対応できるわけである。
実際にコンピュータの世界ではASCII文字の使用割合が高かったことも手伝ってインターネットでのデータ転送やデーターベースへのデータ格納など多くのシーンでUTF-8が使用されるようになったのである。

UTF-16

UCS-2は一見普及したように見えた。しかし、そんな幸せは長くはつづかない。いやむしろ割とあっさりとUCS-2は暗礁に乗り上げる。
数十個程度の文字で事足りている欧米人からしてみたら65536文字で足りないなど全く想像できなかったであろう。
もちろんFar Eastな国々には警戒してはずで、中国語や日本語などは当然考慮されていた。しかし世界には想像以上にたくさんの言語がありたくさんの文字が存在していたのである。
全ての文字を2バイトで表現することができないことを悟った人類は、しかしながらすでに世の中に出回りすぎているUCS-2との互換性を考慮してUTF-16を発明する。UCS-2の範囲内は完全に互換性を維持してUCS-2を超える範囲の文字についてはサロゲードペアという仕組みを用いて2バイトを2つつなげて計4バイトで表現するというとんでもない荒業を繰り出したのである。
全ての文字が同じバイト数で表現できるという理想をかなぐり捨てたなりふり構わない仕様。
かくしてUCS-2の時代の幕は閉じてUTF-16がその役目を引き継ぐことになった。(Javaの文字列も内部をUTF-16とするようになった)
全ての文字を2バイトで表現するという野望が潰えた瞬間であった。
一つの文字は2バイト(よく使う文字)または4バイト(ちょっと珍しい文字)で表現されるのである。

UCS-4(またはUTF-32)

しかし、人類は全ての文字をシンプルに固定の長さで表現するという夢を捨てられなかった。
そこで登場したのがUCS-4(またはUTF-32)である。
UCS-4はすべての文字を4バイト固定で表現する。21億文字をサポートできるそうである。
さすがに地球上の文字をすべて集めても21億文字には到達しないであろう。人類が勝利した瞬間であった。
しかし、唯一残念なのはそれを活用した事例はほとんど聞いたことがない。
各種データーベースでUCS-4(あるいはUTF-32)を文字セットに選択できるようになっている。
ただし通常は1文字4バイトの非効率さにビビってしまって選択できないのである。
※UCS-4とUTF-32は同じものであると考えてしまって問題ない。(たぶん)

まとめ

と、いろいろの紆余曲折を経てUnicodeは進化してきた。
結局は可変長ではあるがその分柔軟性を持ち、可変長であるがゆえに将来Unicodeの文字数が無限に増えても破たんしないと思われるUTF-8は成功したといえるのではないだろうか。
UTF-8はエンコーディング前もエンコーディング後も辞書順が変化しないことや、各文字の先頭バイトが簡単に特定できるなどの優れた特徴ももっているらしい。

文字コードや文字化けで悩まされる世の中からは、確実に進化してきた。後世にこういった不要な不毛な負債を残してはいけないと強く願うのである。