[pgsql-jp: 25214] Re: Windows上JDBC でのエンコーディング

Tsunehisa Kazawa kazawa @ sons.co.jp
2002年 3月 11日 (月) 11:30:00 JST


加澤と申します。

もっぱら Java の話になってしまいます。すみません。

TANAKA Yoshihiro wrote:
> 田中 良浩 です。
[略]
> 文字化けの経験はお持ちですか?

ええ、かなり昔からお付き合いさせていただいております。

[略]
> 論より証拠ですよね...
> 実験してみました。
[略]
> いかがですか、"SJIS"エンコーディングだと化けますよね?
> Javaな方にはご自分の環境で確認していただければ、と思います。

このテストプログラムの問題は、SJIS コンバータを使って Unicode 化
した String に対し、出力段では Windows 環境でのデフォルトエンコー
ディング、つまり MS932 コンバータを暗黙に利用していることにありま
す。違うコンバータを通せば、最終結果のコードが違うものになるのはあ
る意味当然ですよね。出力段に、明示的に SJIS エンコーダを指定した
PrintWriter 等を利用すれば問題なく出力出来るはずです。

そもそも、例えば SJIS コンバータの扱う「〜」と、MS932 コンバータ
の扱う「〜」は Unicode 的に別のコードが割り当てられた別の文字にな
りますから、これらを同一に扱いたいのであれば、Java レベルでそういっ
たコードを書く必要があります。

もう一つの手として、そのシステム内ではどちらかしか現れないように水
際で念入りに調整する、という手段がありますが、僕はその場合、\uff5e
ではなく \u301c 側を使う方が (つまり SJIS コンバータを使う方が)、
のちのち他のコードとの変換などを考えた場合、安全なのではないかと考
えます。ましてや、同じ DB 上のデータを別のマシン上の JavaVM 上に
それぞれ読み込んだ時に、片や \u301c となり、片や \uff5e となるよ
うな実装は最悪だと思います (デフォルトエンコーダを使う、というのは
そういうことです)。

確認したわけではありませんが、今回の場合 DB 側には EUC-JP で格納さ
れ、SJIS コンバータを使って Unicode 化されていることから考えると、
そのコードポイントは \u301c なのではないかと思います (ShiftJIS で
の「〜 (0x81、0x60)」を MS932 エンコーダで読み込んだ時の、\uff5e
ではなく、です)。ですから、この文字を Shift JIS の 0x81、0x60 に
戻したいのであれば SJIS コンバータを使う必要があるのです。これをも
し MS932 エンコーダで 0x81、0x60 に戻したいのであれば、Java レベル
で明示的に \u301c <-> \uff5e 間の文字変換 (違う文字なのだから当然)
を行うのが筋であると僕は思います。

この辺の問題はいろいろと複雑ですが、いろいろなシステム間の相互運用性
を考えるためには避けて通れない部分でもありますから、安易にデフォルト
エンコーディングを使う、という発想ではなく、きっちりと考えるようにし
た方がいいです。

この辺の挙動を確認するプログラムを添付しておきますので、よく考えてみ
てください。

public class test {
    private static String byte2str(byte[] b) {
        StringBuffer strbuf = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            int c = (b[i] < 0) ? b[i] + 0x100 : b[i];
            strbuf.append(Integer.toString(c / 16, 16));
            strbuf.append(Integer.toString(c % 16, 16));
        }
        return new String(strbuf);
    }
    public static void main(String[] args) throws Exception {
        String t1 = "\u301c";
        String t2 = "\uff5e";
        System.out.println(t1 + ":SJIS=" + byte2str(t1.getBytes("SJIS"))
            + ":MS932=" + byte2str(t1.getBytes("MS932")));
        System.out.println(t2 + ":SJIS=" + byte2str(t2.getBytes("SJIS"))
            + ":MS932=" + byte2str(t2.getBytes("MS932")));
        byte[] b = { (byte) 0x81, (byte) 0x60 };
        System.out.println("SJIS=" + Integer.toString(((int) new String(b
            , "SJIS").charAt(0)), 16));
        System.out.println("MS932=" + Integer.toString(((int) new String(b
            , "MS932").charAt(0)), 16));
    }
}

-- 
加澤恒央
Tsunehisa KAZAWA
kazawa @ sons.co.jp
SONS,. Ltd. Programmer



pgsql-jp メーリングリストの案内