http://park3.wakwak.com/~ozashin/sw_tips/webapp_tips/sjis_charset.html
文字コードについて(シフトJISの問題)
|
文字コードをシフトJISで開発し、Windowsのサーバで動かす場合の文字コード問題について示します。
厳密にいうとWindowsが扱う文字コードは、シフトJISでは、ありません。MS932です。または、コードページ CP932ともいいます。MS932は、マ社がシフトJISを拡張して定義したコード体系です。
で、ここで何が問題になるかというと、クライアントへの出力をcharset="Shift_JIS"とか定義して、アプリケーションサーバーなど が一生懸命シフトJISで出力しようとすると、ある文字列が文字化けするのです。ようは、MS932にある文字コードはシフトJISには、ないので、'? 'で出力されるということです。なお、OC4JやJBuilderで利用するtomcatは、MS932で出力しようとするので、あんまり文字化けしませ ん。
Java内部で扱う文字コードは、Unicodeです。ここでシフトJISとUnicodeのマッピングとMS932とUnicodeのマッピング の違いによって、思わぬ、文字化けが発生するのです。ちなみに、JSPファイルにじか書きしてあるもじは、そのまま出力されるので問題はありません。
Javaプログラムを通して、Unicodeからcharsetで定義された文字が出力されるとき文字化けの対象となります。
具体的には、'~'、'∥'、'-'、'¢'、'£'、'¬'などの一部の記号類です。
日本語のUnicodeベンダ依存文字表 http://www.ingrid.org/java/i18n/unicode.html を参照してください。
というわけで、Windowsで動かすのであれば、charsetを"Windows-31J"にしましょう!そうすれば、一部の文字コードを除い て解決です。
JSPの場合は、<%@ page contentType="text/html; charset=Windows-31J" %>と定義します。
Servletでは、
private static final String CONTENT_TYPE = "text/html; charset=Windows-31J";
....
response.setContentType(CONTENT_TYPE);
のように実装します。charset="MS932"でもOKですが、http://www.ingrid.org/java/i18n/encoding/shift_jis.htmlに あるとおり、これからは、Windows-31Jでいくようです。
WAVE DASH問題(TILDE問題)
シフトJISがらみでもうひとつWAVE DASH問題(TILDE問題)というのがあります。これは、JDBCがらみというか、データベースの文字セットの問題というか、誰が根本的な原因かわか らないところがあります。Unicodeの実装が厳密に定義されていないので、ベンダごとで実装の仕方が違っているそうです。
Oracleを例にとって文字の流れを以下に示します。テスト環境は以下のとおり。
OS |
Windows2000 |
データベースサーバ |
Oracle8i R8.1.7 |
DB内部コード |
JA16SJIS |
ある入力フィールドに '~' を含んだ文字列を設定し、それをデータベースへ格納し、参照する場合、文字変換の流れは以下のようになります。
- ブラウザ上では、Windows-31J(MS932)なので、'~'=0x8160
- Javaプログラム内部では、Unicodeなので、JisAutoDetectなどで変換して、'~'=0xFF5E (FULL WIDTH TILDE)
- データベースに格納された結果は、JA16SJISなので、'~'=0x8160
- Javaプログラムがデータベースから文字をGETしたとき、'~'=0x301C (WAVE DASH)
- 0x301Cを応答として出力すると、0x8160にマッピングできないので '?'となる。
この問題は、上記のようにcharsetをWindows31Jにしても回避できません。
ちなみに、Unicodeでいうところの '~' は、0x301C (WAVE DASH)になるのが、Unicodeコンソーシアムでは正しい実装方法だそうです。
(4)で、0x301Cに変換されているんだからOKじゃん、と思いますが、0x8160を0xFF5Eに変換するんだから、0x8160にするに は、0xFF5Eにしてあげなければならないのです。
この問題を回避するには、2通りあります。
- (4)で0x301Cで変換された文字を0xFF5Eに再変換する。
- Oracle9i R9.2以降でMS932がサポートされたデータベース内部コード "JA16SJISTILDE"を利用する。
しかし、(1)では、データベースをアクセスするたび、毎回再変換するので、パフォーマンスが落ちます。(2)では、いまさらOracle9に移行 できる予算がないし、検証しているひまもないという問題があります。
したがって、第3の回避方法として、運用で逃げる('~'は、システム上扱えないコードとしてユーザに我慢してもらう)という手もあります。
ちなみに、私は、多少パフォーマンスが落ちてもOKということで、(1)で再変換の道を選びました。
まぁ、最初からOracle9iR9.2を選んでいれば、OKですけどね。また、検証はしていませんが、EUC-JPでも同様の問題があって、 Oracle9iR9.2からJA16EUCTILDEがサポートされているようです。
参考(Javaのデフォルトコンバータの推移)
Windowsで動かし、JISAutoで変換した場合のデフォルトコンバータは、誰の都合か知りませんが、以下のように変化しました。
まぁ、Windowsで動かす限り、Windows-31Jをcharsetにしておけば、JDK1.4.1以降でもOKのようです。
JDKのバージョン |
デフォルトコンバータ |
実装されたコンバータ |
JDK 1.1.7以前 |
SJISコンバータ |
|
JDK 1.1.8 |
SJISコンバータ |
MS932コンバータが実装される |
JDK 1.2 ~ 1.4.0 |
MS932コンバータ |
|
JDK 1.4.1 |
SJISコンバータ |
|
それ以降 |
保証なし? |
|