Shift_JISのエイリアスの変更について

今日は,みなさんに重要なお願いがあります.

Java 2 SDK 1 2から"Shift_JIS"のエイリアスがSJISコンバータからMS932コンバータに変更されましたが,IANAのcharset定義を正しく実装するため,および現在J2EE分野で発生している文字化け問題の対策として,Java 2 SDK 1.4.1β版から再び元に戻すことになりました. これについては,次のバグレポートをお読みください.

Follow the IANA definition for "shift_jis" charset name
http://developer.java.sun.com/developer/bugParade/bugs/4556882.html

この"Evaluation"の欄に,3月14日付けで次のように記述されています.

"As part of the introduction of newly implemented (using NIO cs API) charset support in Hopper we are reappraising the aliases attributed to the various supported encodings. This particular change will be effected for 1.4.1 beta."

「Hopper(1.4.1)で(NIOの文字集合変換APIを用いて)新しく実装されたcharsetサポートの導入と共に,私たちはサポートされているさまざまな文字エンコーディングへのエイリアスを再検討しています. これに関する変更は,1.4.1β版から有効になるでしょう.」

ただし,日本のJava開発者がこの修正に反対してしまうと,この話は流れてしまうかもしれません.

そこで,今回の変更の主旨と,みなさんのプログラムに与える影響を説明します. ご面倒ですが,この記事を読んで頂くと共に,知人や関連部署などにも,この投稿の内容を理解して頂くように協力をお願いします.

なお,この投稿と同じ内容をhttp://www.ingrid.org/java/i18n/encoding/shift_jis.htmlで公開しますが,ここでは他に実装のチェックやFAQなどの情報も掲載していく予定です.

最後に,このような文字コードの問題は複雑であり,なかなか完全無欠の回答というものはありません. しかし,問題を放置して永久に苦しみ続けるより,一時的な移行のコストを払っても,将来的に問題から開放される方向に努力していきましょう.

風間一洋 (kazama@ingrid.org) NTT未来ねっと研究所


Shift_JISとWindows-31Jの相違点

"Shift_JIS"と"Windows-31J"は,IANAに正式に登録されている文字集合の名称であり,前者はJIS X 0208で定められており,後者はMicrosoftのコードページ932に相当します. この2つの文字集合には,次のような重要な違いがあります.

  1. 収録されている文字が異なります. たとえば,Windows-31JはNEC特殊文字,IBM特殊文字を含んでいますが,Shift_JISは含んでいません.
  2. Windows-31Jは,MS-DOSにおけるNECやIBMの拡張した文字群を収録していますが,一部の重複している文字は,Unicodeの同じコードポイントに割り当てられています. このために,一度読み込んでUnicodeに変換してしまうと,元のファイルに戻すことができないことがあります.
  3. 一部の文字に対して,Unicodeに変換する際のコードポイントが違います(〜, ‖, −, ¢, £, ¬など).

特に最後の違いがあるために,JavaのようなUnicodeベースの環境では,単純にWindows-31JをShift_JISのスーパーセットとして扱うことはできないことに注意してください.


"Shift_JIS"をMS932にエイリアスした経緯

1.1がリリースされた当初は,"Shift_JIS"はSJISコンバータにエイリアスされていました. しかし,Windows-31Jがサポートされていないために,NEC特殊文字などが表示できない,Unicodeのマッピングが違う記号類が文字化けするなどの問題が生じてしまいました.

そこで,日本のJava開発者から,Windows-31Jもサポートして欲しいという要求が出され,それが受け入れられて,1.1.8と1.2からMS932コンバータが追加され,日本語Windows環境のデフォルトも変更されることになりました.

ただし,この時に"Shift_JIS"がSJISコンバータからMS932コンバータへのエイリアスの変更もおこなわれてしまいました. これは,"Shift_JIS"と宣言しながら,実際にはWindows-31Jを用いている場合があったことや,そして従来各社が用いてきたShift-JISを独自に拡張した文字集合のコンバータを個別に追加するかわりに,当面はMS932コンバータで代用しようと考えたからのようです.

もちろん,これを元に戻して欲しいという要望も出しましたが,当時は受け入れられませんでした.

今回,この変更が再考されることになったのは,XMLやWebアプリケーションなど,推奨MIME名を用いなければならないアプリケーション分野の拡大に伴って,利点より欠点の方が深刻になりつつあることが再認識されたからです.


"Shift_JIS"からMS932へのエイリアスが引き起こす問題

"Shift_JIS"からMS932へのエイリアスが引き起こす問題は,次の通りです.

  1. "Shift_JIS"と指定した時の変換結果のUnicodeのコードポイントが他と異なるので,Java以外の環境で処理された場合と結果が一致しない (例,電子署名など)
  2. Shift_JISのデータを処理した時に,「〜」などの記号類に文字化けが生じてしまう

具体的な例を挙げれば,後者の問題に関しては,たとえばServletでは次のような回避コードが使用されてきました.

res.setContentType("text/html; charset=Shift_JIS");
PrintWriter out =
    new PrintWriter(new OutputStreamWriter(res.getOutputStream(),
					   "SJIS"));

また,XMLパーサ"Xerces-J"のように,Shift_JISとSJISコンバータの正しいマッピングを自前で実装して回避していることもあります.

しかし,JavaServer Pagesでは,"SJIS"は推奨MIME名ではないことを無視して,次のようにせざるを得ません.

<%@ page contentType="text/html; charset=SJIS" %>
(注: このコードは本当は誤りです)

1.4からは,推奨MIME名を用いていく方針になり,java.nio.charset.Charset.isRegistered()というメソッドでこの正当性を容易にチェックできるので,近い将来に,この方法も使えなくなりそうです.

つまり,このままではJavaで"Shift_JIS"と"Windows-31J"を使い分けていくことも不可能になるかもしれません.


今回の修正の影響範囲と対処方法

今回の修正の影響範囲と対処方法は,次の通りです.

1, プログラムやデータ,通信で"Shift_JIS"と明示的に指定していない/されない場合
プログラムの実行に影響はありません.
2, プログラムやデータ,通信で"Shift_JIS"と明示的に指定している/される場合
ほとんどがWindows-31Jを用いたデータを扱っているにもかかわらず,誤って"Shift_JIS"と指定していた場合だと思いますが,拡張された文字や一部の記号類(〜, ‖, −)が'?'に文字化けしますので,正しく"Windows-31J"と指定してください. なお,この修正は1.4.1bを待つ必要はありません.
a) Servletの場合
res.setContentType("text/html; charset=Windows-31J");
PrintWriter out = res.getWriter();

b) JSPの場合
<%@ page contentType="text/html; charset=Windows-31J" %>
3, "MS932"と明示的に指定していた場合
プログラムの実行に影響はありません. ただし,"Windows-31J"に書き換えることを薦めます. なお,この修正は1.4.1bを待つ必要はありません.
4, "SJIS"と明示的に指定していた場合
プログラムの実行に影響はありません. 1.4.1b以降では,"Shift_JIS"でも正しく動作するようになりますので,"Shift_JIS"に書き換えてください.

FAQ

Q 正しく指定されているかどうかは,どのようにチェックできますか?
A Unicodeのマッピングが違う文字 (〜, ‖, −)が化けていないかをチェックしてください.
Q MS932コンバータが廃止されるのでしょうか?
A NIO対応で名前は変わるかもしれません(互換性は維持されます)が,現在と等価なコンバータが存続するはずです.
Q Windows環境のデフォルト文字エンコーディングが変更されるのですか?
A Windows環境のデフォルトの名前が変わるかもしれませんが,現在と等価なコンバータが使用されるはずです.
Q なぜUnicodeへのマッピングに違いが出たのでしょうか?
A 次のような理由からのようです.
Q Javaではベンダ固有文字を使用してはいけないのでしょうか?
A そうではありません. データに使用されている文字や,Unicodeへのマッピングに違いや揺れが出ないで正しく情報交換できるように,正しく区別して使用していきましょうということです.
Q JavaでNEC漢字コードを使用したい場合には,どうすればよいですか?
A Windows-31Jへの移行が目的の場合には,Windows-31Jを使用します. ただし,一度変換した後にNEC漢字コードに戻すことはできない(http://www.microsoft.com/japan/support/kb/articles/JP170/5/59.asp参照)ので,相互変換をおこないたい場合には,1.4で追加された文字集合変換SPIを用いて,新しいコンバータを作成してください.
Q 円記号 (0x5C)のUnicodeへのマッピングは変更されますか?
A 現在,0x5Cは,SJISコンバータとMS932コンバータのどちらもU+005Cに変換していますので,変更はないと思います.
Q Xerces-Jは,"Shift_JIS"と"Windows-31J"をどのように扱っていますか?
A Xerces-Jは,"Shift_JIS"と指定された場合にはSJISコンバータを使用しています. "Windows-31J"はまだサポートされていないようですが,将来的にサポートされると思います.
Q Unicodeから"Shift_JIS"や"Windows-31J"に変換する時に,多対一に対応させれば,文字化けは防げるのでは?
A その提案もおこないましたが,却下されました. この理由としては,それぞれの文字集合のUnicodeへのマッピングはその制定団体が決定するものであること,また多対一に対応するマッピングをおこなうと相互変換(round-trip conversion, 変換した後に逆変換すれば元に戻る種類の変換)が損なわれるからのようです.

付録A Shift_JISとWindows-31Jの定義

これは,IANAに登録されている文字集合名のリスト (http://www.iana.org/assignments/character-sets) から,Shift_JISとWindows-31Jの定義を取り出して,日本語訳したものです.
名前: Shift_JIS (推奨MIME名)
MIBenum: 17
典拠: この文字集合は,csHalfWidthKatakanaに,JIS X 0208の図形文字を追加
      した拡張です.このCCSは,JIS X0201:1997とJIS X0208:1997です.
      完全な定義は,JIS X0208:1997の付録1で見ることができます.
      この文字集合は,トップレベルのメディアタイプ"text"に使用できます.
エイリアス: MS_Kanji 
エイリアス: csShiftJIS
名前: Windows-31J
MIBenum: 2024
典拠: Windowsの日本語です.Shift_JISに,NEC特殊文字 (13区),NEC選定IBM
      特殊文字 (89区〜92区), IBM特殊文字 (115区〜119区)を含めた拡張です.
      このCCSは,JIS X0201:1997,JIS X0208:1997および上記の拡張です.
      この文字集合は,トップレベルのメディアタイプ"text"に使用できますが,
      限定された用途,または特殊用途に用います (RFC2278参照).
PCL記号セット ID:  19K
エイリアス: csWindows31J

付録2 Shift_JISとWindows-31JのUnicodeへのマッピングの違いの参考資料

なお,この問題については,次の資料に詳しく説明されています.