Java: 出力時に化ける文字一覧

Unicode で持っている段階では「正しい」のに、従来の日本語エンコーディングに変換する時点で、変換に失敗して "?" に化けてしまう文字がある。
例えば、"〜" (全角の波ダッシュ) を "Shift_JIS" として Unicode に変換した場合、"Windows-31J" に再度変換しようとすると、"?" に変わってしまう。これは、Java に載っている各コンバータのマッピングがずれていることが原因だ。
上記の "〜" の場合、"Shift_JIS"、"EUC-JP"、"ISO-2022-JP" の各コンバータでは、Unicode の U+301C (WAVE DASH) に対応付けられている。ところが "Windows-31J" のコンバータでは U+FF5E (FULLWIDTH TILDE) に対応付けられている。このため、入力と出力でコンバータを変えると、出力した時点で化けてしまう。
この問題は、主に "〜" について知られているため、例えば Wikipedia の記事では、「WAVE DASH - FULLWIDTH TILDE問題」と書かれている。しかし、実際には他にも同じ理由で化ける文字がある。

Javaの日本語関連コンバータにおけるマッピングの違い
http://www.ingrid.org/java/i18n/encoding/ja-conv.html

このページの調査結果を元にすると、全部で 6 つの文字が該当する (CP943、CP943C および古い MacTEC については、今回は考えないことにした)。

文字 コード (シフト JIS) Shift_JIS/EUC-JP/ISO-2022-JP コンバータでの対応付け Windows-31J コンバータでの対応付け 備考
〜 (波ダッシュ) 0x8160 U+301C (WAVE DASH) U+FF5E (FULLWIDTH TILDE) -
− (マイナス) 0x817C U+2212 (MINUS SIGN) U+FF0D (FULLWIDTH HYPHEN-MINUS) -
‖ (二重垂直線) 0x8161 U+2016 (DOUBLE VERTICAL LINE) U+2225 (PARALLEL TO) -
¢ (セント) 0x8191 U+00A2 (CENT SIGN) U+FFE0 (FULLWIDTH CENT SIGN) ※1
£ (ポンド) 0x8192 U+00A3 (POUND SIGN) U+FFE1 (FULLWIDTH POUND SIGN) ※1
¬ (否定) 0x81CA U+00AC (NOT SIGN) U+FFE2 (FULLWIDTH NOT SIGN) ※1

したがって、出力する際、これらのエンコーディングへの変換を行う前に、文字を置換してやれば、とりあえず表示は可能ということになる。例えば、Windows-31J で出力したい文字列に U+301C が含まれていたら、出力直前に U+FF5E へ置き換えればいい。逆に、ISO-2022-JP で出力したい文字列に U+FF5E が含まれていた場合は、U+301C へ置き換えることになる。
ただし、上表のうち下 3 つ (備考欄に ※1 があるやつ) については、Windows-31J での出力時には考慮しなくていい。Unicode への変換時には Windows-31J とそれ以外で結果が変わるのは上の表の通りなのだが、そのどちらであっても、Windows-31J コンバータは同じバイト列に変換するからだ。残り 3 文字も同じように対応してくれればいいのに、とも思うが、元々 Windows-31J コンバータは「Windows の動作に合わせたコンバータ」という位置づけなので、Windows が対応しない限りどうしようもないのかもしれない。

(この記事の更新履歴)

[2007-04-16] 表中「−」を「ハイフン」と書いていたが、これは「マイナス」の誤りだったので修正。