私はWindowsが好きだ。
特にIE6がいい。私は今日、IE6がどんなによくできているかを思い知った。
webページの文字コードを判別する手がかり(というあたりが諸悪の根源なのだが)はいくつあるか。私の知るかぎりでは3つ、
1. レスポンスヘッダ
2. meta要素
3. テキスト
そしてXHTMLなら、これに加えて、
4. XML宣言のencoding
となる。が、XHTMLのencodingを間違えるような間抜けは無視できるので、XHTMLなら文字コード判別の必要はない。
この世でもっとも正しい方法は、レスポンスヘッダである。が、レスポンスヘッダ中にcharsetが表示されていると信じるのは、サンタクロースの存在を信じるよりもはるかに難しい。
meta要素はサンタクロースよりも信じられる。少なくとも日本語のページでは、かなりの割合でmeta要素の存在が期待できる。
最終決裁者が、テキストだ。meta要素やレスポンスヘッダがなにを書いていようと、テキストが文字化けしていればそれは文字化けである。なにしろ世の中には、HTMLをメモ帳で手書きするよう指導する呪われた入門サイトがあるので(彼らに三度アナテマ)、呪われた人々が「charset=x-euc-jp」とmeta要素に書き込みつつUTF-8で保存しているかもしれない。こういう呪われたHTMLは表示できないようにすべきだったが、もし人々がそれほどまでに正しかったなら、人間は天使と区別がつかないだろう。
このような状況のもとで、webページの文字コードを判別する仕組みをサーブレットに組み込むには、どうすればいいか。まず大まかな流れを考えよう。
正しい人は、正しい方法を尊重する。レスポンスヘッダにもしcharsetが設定されていれば、これがmeta要素やテキストに優先されるべきだ。もしなければ、次にmeta要素が来る。そして最後の手段が、テキストデータからの推測だ。
では早速そのようなアルゴリズムを実装しよう――などと思った人はプログラマではない。プログラミングとは、不労それ自体によって生産する技芸である。
レスポンスヘッダのcharsetを最小限のコードで取得できるのは、おそらく、Jakarta Commons HTTPClientである。これをちょっといじり、レスポンスヘッダのcharsetのあるなしを取得できるようにする。
レスポンスヘッダにcharsetがなければmeta要素を当たる。これをもっとも簡単確実にやってくれるのはおそらく、NekoHTMLだ。ここでもまた、meta要素にcharsetのあるなしを取得できるようにいじる必要がある。
自動判別は、私の知る限り、jchardetのほかに選択肢がない。StringのコンストラクタのJISAutoDetectは、UTF-8やMS932でこける。
さて諸君、ここで残念な知らせがある。
これだけやってもまだ、これほどやってもまだ、満足のいく判別にはたどりつけない。たとえば、上の仕組みを素のままでhttp://www.yahoo.co.jpに適用すると、GB2312と判別される。どうやらEUC-JPはその仕組み上、自動判別を間違えやすいらしい。一応の救済策はあり、jchardetに日本語判別を指定すると、正しく判別される。が、日本語判別を指定した状態では、他の文字コードをまったく判別できなくなる。
もしサーバ上にIE6さえあれば、こんな苦労はすべてなくなるのだ。この世のサーバがすべてWindowsになる日も、そう遠くないだろう。
前言撤回。
中身を開けてみたら、NekoHTMLよりもHTMLParserのほうがいい。これだとHTTPClientがいらないので、話がずっと簡単になる。
また、http://www.yahoo.co.jpのレスポンスヘッダにはcharsetが設定されていた。なぜ設定されていないと思ったのか、いまではよくわからない。