#navi_header|Java| Shift_JIS, MS932, Windows-31J の取り扱いについて実験する。 これらは特にサーバーサイドのJavaを扱う上で何かと文字化けの原因として取りざたされている。 %%今回示す例では、日本語の自然文で普通に使用される '' ~ '' が簡単に文字化けしてしまっている。%% 特にややこしいのが"Shift_JIS"と"MS932"(CP932)系の違いである。 Windows上でのShift_JISは、正確にはShift_JISをベースとして空いている外字領域にNECやIBM由来の特殊な文字を配置したエンコーディングであり、これが "CodePage932", CP932ともMS932とも、Windows-31JともMS-Kanjiとも呼ばれているエンコーディングである。 今回の記事で例示している中で、「~」「・」は本来のShift_JISに配置されているため、これだけならコンパイル時にソースファイルのエンコーディングを「Shift_JIS」と指定してもWarningは出ない。(Warningは出ないが、実際に実行してみると文字化けする。この原因は後述。) 「㈱」が混じると、こちらはCP932で13区74点、つまり本来Shift_JISには無い外字領域に配置された文字になるため、"Shift_JIS"を指定すると文字がマップできないとWarningが出力される。 * "~"や"㈱"が混じったJavaソースを用意する。 public class EncodingW31 { public static void main(String[] args) { System.out.println("Windows-31J ~・㈱"); } } * コンパイルし、実行してみる。 ** ケース1:Shift_JISとしてコンパイル・実行 &image(87) 上図に示すとおり、見事に文字化けしている。下はclassファイルをUTF-8対応のエディタで文字コード自動認識で開いた図。 &image(88) ** ケース2:MS932、あるいはWindows-31Jとしてコンパイル・実行 &image(89) 上図の通り、文字化けせずに表示できた。なお、エディタで開いてみると先と同じく、自動認識ではSJISと判定されてしまった。 なお、こちらの例では"MS932"としていしてコンパイルしたが、 '' "Windows-31J"を指定しても同じクラスファイルが生成された。 '' (MD5チェックサムが同一) * 結論 %%サーバーサイドで入力される文字コードがSJISが想定された場合は、"Shift_JIS"で受け取るのではなく"Windows-31J"あるいは"MS932"として受け取るべきである。%% ''日本語版Windowsにより生成されたCP932の文字列を受け取ることが想定される場合は、'' "Shift_JIS"で受け取るのではなく"Windows-31J"あるいは"MS932"として受け取るとよいだろう。 Webアプリケーションの場合で、入力フォームがUTF-8やEUC-JPの文字コードで構成される場合は、クライアント=Webブラウザが入力フォームと同じ文字コードに変換して送信すると予想されるため、"UTF-8"や"EUC-JP"で受け取るとよいだろう。 ** 補足:「㈱」無しで"Shift_JIS"でコンパイルしても文字化けする理由 「㈱」無しで "-encoding Shift_JIS" とした場合、コンパイルでこそWarningは出ないが、実際にうごかしてみるとやはり文字化けしてしまう。これは"~"(1区33点, 0x8160)のマッピングが原因である。 Javaは"~"について、Shift_JISとMS932で異なるUnicodeコードポイントにマッピングする。 - Shift_JIS -> U+301C, WAVE DASH (UTF-8: 0xE3809C) - MS932 -> U+FF5E, FULLWIDTH TILDE (UTF-8: 0xEFBD9E) これが、外部からの入力をJavaの内部に変換する場合のマッピングとなる。 そしてJavaの内部でのWAVE DASH, FULLWIDTH TILDEを外の世界にマッピングするときが問題となる。 - U+301C(WAVE DASH) -> '' "MS932" 以外のみ '' Shift_JISの0x8160にマッピング可能 - U+FF5E(FULLWIDTH TILDE) -> '' "MS932" のみ '' Shift_JISの0x8160にマッピング可能 Windows用のJavaVMで普通にSystem.out.println()する場合はMS932が「内→外」変換として使われる(PrintStreamの文字列出力は、プラットフォームのデフォルトの文字エンコーディングを使ってバイトに変換される)。 従って、"-encodign Shift_JIS"でコンパイルしたclassファイル中の「~」(U+301C WAVE DASH)はMS932ではマップされないため、"?"として文字化けすることになる。 * 参考(Windows-31JとJava関連) - http://www.atmarkit.co.jp/fjava/rensai3/mojibake01/mojibake01.html - http://www.javaroad.jp/servletjsp/sj_servlet13.htm - http://www.ingrid.org/java/jserv/i18n/corruptedchar.html - http://www2d.biglobe.ne.jp/~msyk/charcode/cp932/Windows-31J-charset.html * 参考 ("~"での文字化け, JavaでのUnicodeのマッピング問題など) - "Java Character Encodings" -- http://www.ingrid.org/java/i18n/encoding/ - "Javaの日本語関連コンバータにおけるマッピングの違い" -- http://www.ingrid.org/java/i18n/encoding/ja-conv.html #navi_footer|Java|