プログラマのための文字コード技術入門;あなたなら、どう設計して拡張する?

 文字コード関連の記事で書いていた「プログラマのための文字コード技術入門」ですが、先日読み終わりました。

 はっきり言って凄まじくマニアックな本です。

 日本語の文字について、どのような文字が入るかと、文字を区別するための番号を決めてあるJIS X 0208と、それの拡張であるJIS X 0212JIS X 0213といった符号化文字集合について、どの漢字がどう入っていて、のちの規格でどう拡張して…みたいな話が延々書いてあります。

 この符号化文字集合というのは、前回推定していた文字コードとはまた別の概念で、「符号化文字集合で定められた値を、実際のバイト列にどう落としこむか」を決める規格がShift_JISEUC-JPISO-2022-JP(JIS)といった「符号化方式」です。

 これについてももちろん詳しく書かれています。これらの「符号化方式」は、同じ番号(JIS区点番号)を違うバイト列に変換しているだけなので、これらの間では(ほぼ)機械的に変換を行うことができるわけですね(jcode.pl、めっちゃ懐かしいです)。

 ちなみにUnicodeはこれらの規格とはあんまり関係なく、それぞれの文字について、別の番号(Unicodeコードポイント)が決められているため、Shift_JISなどの方式と相互変換しようとすると、絶対に文字と文字の対応テーブルが必要になってきます。これに関してももちろん、結構細かく書いてあります。

 そんな感じで詳しく文字コードについて書いてるのですけど、はっきりいって、もー複雑なんですよ!これが!!

 結構集中して読んでたのですが、それでももう全然覚えてないです…。Shift_JISにしても、後々追加した漢字が使えるようになったShift_JIS-2004っていう別規格があって、どうたらこうたら…なんかもう訳わからないです^ρ^

 JIS X 0208やJIS X 0213も、こっちの規格とこっちの規格で文字がかぶってるだの、新しい規格で追加したせいでShift_JISにMicrosoftが独自に追加した機種依存と被ってしまっただの…。

 UnicodeとJIS X系で変換するときに、JIS X->Unicode->JIS Xってやったら元に戻るようにトリッキーな救済措置をしたら、今度はそれが仇になって、他の国の漢字と整合性が保てなくて、違う言語で同じUnicodeでの漢字がスワップしてしまったり…(”“と”“問題)

 もう文字コードを自力で扱ったりしないよ(世界丸見え風)と固く決心させてくれるだけでも、十二分に良書なのではないか!と思います!(割りと真剣な目で

別の視点から読んでみる:自分が拡張しなきゃいけなくなったら、どうする?

 さて、この本で文字コードの複雑さに頭を悩ませるのも一興ですが、また違った楽しみ方があります。それは、自分が文字コードの開発者になったら、どう拡張したかな?というのを、色々考えてみるという楽しさです。それこそプログラマなら、一度は考えてみるべき!です!

 最初期の文字コ-ドは、もちろん、ASCIIに代表される英語だけの文字コ-ド。符号化文字集合と符号化方式のようなレイヤーに別れていない、素朴な仕様です。1960年代に生まれました。

 しかし、英語のアルファベットだけですから、ヨ-ロッパの国々のàみたいな別種の文字を扱うことができませんし、$記号はあるのに、自分の国の通貨記号がないのも不便です。そして、考えなければならないのは、この時代のコンピュ-タは本当にスペックが今に比べると低かった、ということ。できる限り、ASCIIで使っている7bitの範囲内で文字を表現したかったようです(その後出てくる文字コ-ドは8bitが主流だし、どうしてなのかいまいち分からないです…7bitしか扱えないことで有名なSMTPは80年代ですし…この辺の事情詳しい人居たら教えてね!)。

 さて…どう拡張するべきでしょう…。ASCIIは、128種類の殆どを使いきってしまっています。制御文字も、きっと当時はみんな必要なものだったのでしょうから、自分たちの言語の文字に使うこともできそうにありません。

 そのとき、標準として選ばれたのが、ISO/IEC 646です。結局、ASCIIを基本としつつ、各国ごとに文字コ-ドの規格を分離し、特殊記号に関しては自分たちで決めてね…といった感じの規格です。文字コ-ドの規格自体には、「どの文字コ-ドなのか」を区別する規格はないため、別にどの文字コ-ドなのかの情報を持っていなければなりません。そう、もうこの時点で「文字化け」という概念が発生しているのです

超有名な円マークとバックスラッシュ問題

 たとえば、日本では、ISO 646の一種としてJIS X 0201が制定され、この規格では、ASCIIのうちの∖の代わりに¥が、˜の代わりに‾が宛がわれました。円マ-クと\…そう、この文字化け、今でも非常によく見かけますよね!私のBlogでも、たまに円マ-クがバックスラッシュになってて、「ワンコインは∖500」みたいな文章になったりしてて、なんだかよく分からない事になってます。

 表示が化けるだけなら、まだ良い方です。そう思って、円マークとバックスラッシュに関しては、区別を適当にする…という感じで今まで対策がされてきました。が、この円マ-クとバックスラッシュの区別が適当な事を利用すると、クロスサイトスクリプティングできちゃったりします。これらの面倒な問題は、すべてこのISO 646の規格にまで遡っているのです…。。。

三者三様の「半角カナ」「全角カナ」問題

 さらに、このJIS X 0201では、部分的に、日本語にも対応しました。でも、当時のコンピュ-タの性能は、グラフィックもCPUもあまり高く無いため、カタカナだけです(ドット数が低いと、まるっこい文字より直線的な文字のほうが表現しやすかったんですかネ)。これも、現在でも「半角カナ」として、残っています。

 この規格だけなら何の問題もありませんが、後々JIS X 0203などで拡張された際に付け加えられた「全角カナ」もあり、こちらもShift_JISやEUC-JPで使うことができます。同じ文字を二通りで表せるのは、違う文字を一通りで表してしまった円・バックスラッシュと同じく、色々と問題が発生します…。

 たとえば、「半角カナ」で「アイウエオ」と書かれた文章を検索するときに、「全角カナ」で「アイウエオ」で検索してもヒットしない、ということです。これは不便ですし、掲示板のNGワ-ドを実装するときにすり抜けられてしまったり、SPAMフィルタのために文章を単語ごとに分離させるときも、同じワ-ドが違うものになってしまったり、妙な事になってしまいます。

 そもそも、感覚的に、同じ文字が違うバイト列で表現されてるのは絶対変です。よくサービスの登録画面とかで「住所(全角で入力)」みたいなのがありますが、なんでそんな事しなきゃいけないんでしょう。カタカナはカタカナ。そうでしょう?

 う~ん、この「半角カナ」、どうするべきだったのでしょう…。EUC-JPでは、この「半角カナ」を使うには、あるエスケープシーケンスをおいた後に続けないと、使えなくなりました。これはどういう事かというと、JIS X 0201そのままのデータを、EUC-JPとして直接読むことはできません。一旦コード変換が必要になります。今では何でもありませんが、JIS X 0201のような1バイト文字コードしか扱えない環境が多く、相互でやり取りすることが多かった時代では、結構不便だったようです。

 逆に、Shift_JISはJIS X 0201をそのままにしつつ、JIS X 0201で使っていない部分に、半ば無理矢理(本来は文字が入らない、制御コードの領域も使ってしまいました)、JIS X 0213の漢字を格納しています。互換性やJIS X 0201しか扱えない環境とのデータのやり取りは簡単だったようです。が、無理やり押し込んでしまったため、例の「表示」が「侮ヲ」になる、5C問題が発生してしまいました。

 電子メールで使われるISO-2022-JPは、バッサリと切り捨ててしまいました。もし半角カナの含まれたJIS X 0201や、Shift_JIS、ISO-2022-JPから変換したい場合は、すべて「全角カナ」に統一され、全角と半角の区別が失われる事になりました。

 このように、三者三様の半角カナの扱い。どれが一番だと思います?現状ならISO-2022-JPのように廃止で良いと思うのですが、当時の状況を考えると、そうでもなかったようです。

 ちなみに、UTF-8全盛の現在でも半角カナは生き残っていますが、Unicodeの方針としてShift_JIS->Unicode->Shift_JIS、のように変換したら、元のShift_JISと同じバイト列が得られる、ということを基本としているようで、これを満たすために「半角カナ」はまだ生き残っています。Unicodeに採用されてしまった以上、半角カナはこれからもしぶとく生き残っていくでしょう。

 なお、「半角カナ」は1バイトのイメージが強いと思いますが、UnicodeやEUC-JPでは、もはやそうではありません。表示する上で半分の太さの文字にしているというだけです。

 似たような問題が、この本にはいくつもいくつも出てきます。これらの問題も含めて、どうするべきだったのか、当時の技術の都合も想像しながら読んで「おれのかんがえたさいきょうのしよう」を考えてみると、一興かもしれません。