文字エンコーディング名の狭間
仕事柄Javaと.NETを行ったり来たりするライブラリィを書いていますがその間を行き来するデータの殆どはHTTPプロトコルを使用したRESTかXML(XML over HTTP)でやり取りするように実装しています。例えばJavaと.NETでデータ交換を目的として以下のXMLをJava側で生成したとします。
<?xml version="1.0" encoding="Windows-31J"?>
<foo>
<foobar>ふーばー</foobar>
</foo>
また、以下の様なコードでJava側から出力されたレスポンスストリームも同様のエンコーディングのはずです。
response.setContentType("text/html;charset=Windows-31J");
エンコーディング名"Windows-31J"はJ2SE1.4.1から導入されたMS932の新たなエイリアスでありWindows系のプラットホームではコンバータに問題のあるShift_JISでは無くこちらを使うのが推奨されています。※
これで.NET側でも普通に解釈できるだろうと思い.NET側でこのXMLをストリームとして読込む際にエンコーダのインスタンスをEncondingクラスから取得しようとすると「そんなエンコーディング名知らんわ」と怒られてしまいます。"Windows-31J"は正式なIANA登録名だから.NETでもサポートされているんじゃないの? と以下のようなコードを書いて調べると
class EnumEncoding { public static void Main() { //全て列挙してみる for (int i = 0; i < 65535; i++) { try { Encoding enc = Encoding.GetEncoding(i); Console.Write(i); Console.Write(", " + enc.WebName); Console.Write(", " + enc.EncodingName); Console.WriteLine(); } catch {} } } }
なんと.NETのEncodingクラスには名前"Windows-31J"はどこにも登録されていないのです。
ではシステムのサポートキャラクタセットとしてレジストリのMIMEにも"Windows-31J"は存在しないのかと思い自分の環境(WindowsXP/Pro)のレジストリHKEY_CLASSES_ROOT\\MIME\\Database\\Charset配下を探してみるとやはり見つかりません。がしかし代わりに使えそうな"csWindows31J"という名前がありました。これはIANAでは"Windows-31J"のエイリアスとして登録されている名前なのでXML宣言"encoding="csWindows31J""と書けば"Windows-31J"と同じになるのでこれで解決かと思ったのですが.....
このエンコーディング名"csWindows31J"ですがWindowsXPのレジストリ上では"Shift_JIS"のエイリアスとして登録されているのです。
まとめ
1..NETでIANA登録名である"Windows-31J"が何故かサポートされていない
2.本来"Windows-31J"の別名である"csWindows31j"が何故か"Shift_JIS"の別名である
従って現状、Javaと.NET間で日本語を含むXMLやHTMLを正しく交換したりプラットホーム間で申し合わせてストリームをやり取りする為にエンコーディングを合わせようとするとJava側で最もポピュラーと思われる"Windows-31J"は使用できません。結局はプラットホームを限定しないケースでは事実上utf-8しか選択肢がありません。(Shift_JISは特定のUNICODE文字やDBMS等で問題が出る事が避けられないので使わないほうが良いです)
少し前にSunとMSとの和解及び戦略的な連携がニュースになりましたが連携言うならまずはこの辺から合わせて欲しいものです。
追記:※Javaの日本語エンコーディングのエイリアスの経緯に関しては風間氏のがとても参考になります。
追記:エンコーディングの列挙のコードですが.NET2.0から列挙用のメソッドが追加されたのでもっとすっきりと書けますし重複も無く速度も段違いに速いです。
//for.NET2.0 beta2 class EnumEncoding { public static void Main() { foreach (EncodingInfo info in Encoding.GetEncodings() ) { Console.Write(info.CodePage); Console.Write(", " + info.Name); Console.Write(", " + info.DisplayName); Console.WriteLine(); } } }