UnicodeであるStringオブジェクトを指定したエンコーディングで変換したバイト配列を得ます。
指定できるエンコーディングでよく使うものは以下のような感じです。
(ちょっと調査不足でいいかげんなので注意。今度直します)
正確なものはJDKドキュメントの「国際化」の項を参照してください。
風間さんのページをご紹介しておきます.
| ISO-8859-1 | US-ASCII相当。上位バイトは捨てられる。 |
| ISO-2022-JP | JISコード。メールでおなじみ |
| Shift_JIS | JDK1.1まではSJIS相当、JDK1.2からはMS932相当となっています。 |
| MS932 | Windowsネイティブなコード系 |
| SJIS | 古いMS-JVMのみMS932相当のマッピングのようです。 古いIEでファイル書き込みを行って見て発覚しましたが。正確なバージョンはよく覚えていません。 たぶんBuild29??というやつだと思います。 最近のMS-JVMではそういうことも無いようです。ややこしい。 |
| EUC_JIS | Unixでおなじみ。半角カナは使わないっと |
尚、デフォルト(無指定)ではプラットフォームのデフォルトエンコーディングとなります。これがJDKバージョンなどによって違うので要注意です。
「文字列が全然表示されない」というのは、他のFAQにお任せするとして、ここでは、一部の文字だけが意図と異なる文字で出力される件です。
特によく問題になるのは、波線記号(WAVE DASH)/マイナス記号(MINUS SIGN)他いくつかの文字だけが'?'(0x3f)になってしまうという物です。
これはさまざまな文字コード系からUnicodeにコード変換する段階で起こる問題によります。各種文字コードからUnicodeに変換するときに使われる変換表に(同じ文字コード系からでも)いくつかの種類があり、そのどれを使うかによってUnicodeの異なる文字に変換される場合があります。
この変換表の相違については「XML日本語プロファイル」に詳しく書かれています。
しかし、異なる文字コードに変換されたからといって、「どちらか一方の変換表が間違っているせいだ」とも言い切れない事情があるようです。
それはともかく、同じ文字が異なる変換表を使ってUnicodeに変換された場合に、異なる文字コードになるということは、文字コードの比較による検索などに失敗するようになるということです。
私のメインがWindows環境なので、そういう例ばかりで恐縮ですが、'〜'(WAVE DASH)という記号に関して、Unicodeでは、0x301c/0xff5eという二通りの表現があります。(というよりその何れかに変換されてしまう)
その変換を行ったコンバータで出力も行っている限りは問題は発生しませんが、異なるコンバータ、つまり、入力エンコーディングと出力エンコーディングが異なる場合には正しく逆変換が行われないケースが発生します。
特に入力文字列が複数のエンコーディングで書かれていると最悪の状況になります。
(どのコンバータを使ってもどこかの文字が化ける)
これはコンバータで吸収してくれても良さそうなものだと私は思いますが・・・。
# unmatch(0x3f)にするくらいだったら両方のUnicodeから変換できてもよかろうに
こんなことを注意しながらプログラミングするのは馬鹿らしいので、
入力エンコーディングと出力エンコーディングは完全に一致させるのが懸命でしょうね。
しかし、native2asciiを使ったリソースファイルの元ファイルの文字コードは知るすべがないわけだから(JIS固定!っとか言っちゃえばいいんだけど)出力エンコーディングを入力に合わせようとしても無理だよねえ。XMLだって、encodingは〜〜固定!って言っちゃえば出力エンコーディングとあわせられるけど、parse後に元のエンコーディングを知るすべが無いのは同じだし。
回避方法1:以下のような約束を守る。
しかし、それではUnicodeエスケープを解釈しないべたのテキストファイルリソースなどでは回避できません。
# そんな物ははなから出力エンコーディングと同じコードで書くように
# 指示しているはずなので普通は問題は出ないとは思いますが。
## 私はプレーンテキストなリソースを好きな文字コードで書いてもらって、
## パラメタでエンコーディング名も指定できるようにしたいのです!!
回避方法2:変換揺れを吸収する出力ストリームをかませる。
出力エンコーディングに応じて、他の入力エンコーディングで異なるUnicodeに変換されて、そのままでは正しく出力エンコーディングに変換できないような文字に関してだけ補正を行うラッパストリームを使う。
OutputStreamWriterの外側にそのエンコーディングに応じて異なる補正を行うようなラッパストリームを被せる。
出力エンコーディング毎にクラスまたは処理を追加しなければならないので、作るのが大変。
取り敢えず、"ISO-2022-JP""MS932"だけに対応したWriterを作っています。
まだ、ちゃんと作る価値があるかはっきりしていないので参考用ソースとして置いておきます(Shift_JISコメントです)。こういうことをしようとしているってことで。
国際化されたプログラムの条件として、特定の言語やプラットフォームに依存した文字コードを使用してはならないというのがあります.
そこでメッセージの文字列などは国と言語に応じたリソースファイルを用意し、プログラムの方では
国コード/言語コードに応じたリソースセット(ファイル)から、
特定のキーに応じたローカライズされたメッセージを取り出して使用する必要があります.
以下のようなリソースファイルを作成しておきます.
import java.util.*;
public class Resource extends ListResourceBundle {
public Object[][] getContents() {
return contents;
}
static final Object[][] contents = {
{"key1","Open"},
{"key2","Save"},
{"key3","Exit"},
{"key4","Edit"},
:
:
};
}
[Resource_ja.java]
import java.util.*;
public class Resource extends ListResourceBundle {
public Object[][] getContents() {
return contents;
}
static final Object[][] contents = {
{"key1","開く"},
{"key2","保存"},
{"key3","終了"},
{"key4","編集"},
:
:
};
}
_jaは日本語用リソースです。
そして、プログラム中では以下のように文字列を利用します。
ResourceBundle resources_;
resources_ = ResourceBundle.getBundle(
"Resource",Locale.getDefault());
try {
str = resources_.getString("key1");
} catch (MissingResourceException mre) {
str = null;
}
上記のように文字列を扱う事で、とりあえず英語圏と日本で正常に文字表示が可能になります。
サポート言語を増やす場合はリソースファイルを追加するだけですみます。
なおリソースファイルは下記のように.propertiesとして記述しても良いです。
key1=開く key2=保存 key3=終了 key4=編集 : :
呼び出し部分はまったく変わりませんのでこちらの方が楽です。
ただし、こちらはこのファイル自体をクラスファイルと同じディレクトリに配置する必要があるので、コンパイラの出力先を変えている場合はご注意。
また、native2asciiでUnicodeエスケープに変換しておかなければなりません。
JavaおよびHotJavaは米国Sun Microsystems社の商標または登録商標です.