2012年5月7日月曜日

Character Encoding

Most fundamental in dealing with Unicode characters — whether in interactions with files, webpages, or in database access — is proper use of character encoding. Once the character encoding has been properly configured, programming Unicode, or international, applications becomes a transparent process. For example, in writing Unicode characters to a text file, you need to specify a Unicode encoding for the file to avoid loss of data; when reading back, you need to use the same encoding to decode what you wrote. For database applications, you need to ensure the database encoding is properly configured so that it can accept storage of Unicode data. For instance, SQL Server 2000 uses UTF-16 as its encoding, while MySQL server's encoding can be set to UTF-8 to handle international characters. Once configured properly, programming should be straight forward; Unicode characters will be handled correctly and automatically between the Java applications and the servers.

You can directly type Vietnamese in Java source code using any appropriate Vietnamese input methods, save them in a Unicode Transformation Format, such as UTF-8, and then specify the appropriate encoding when compiling them. Or you can escape them by using native2ascii tool supplied with JDK. The main advantage of using Unicode escape sequences is that the source is independent of file encoding, but at the expense of code readability and modifiability.

Note: When saving in UTF-8 format, be sure to use an editor that does not emit BOM (byte order mark) signature at the beginning of the file. The BOM characters will cause javac compiler to fail. For instance, Windows Notepad is one of such editors, while jEdit or JCreator is not.

NewMain.java:

/* // EFBBBF is UTF-8 BOM signature; needs to be removed from the source code
* NewMain.java
*
* Source saved in UTF-8 format
*/
import javax.swing.JOptionPane;

public class NewMain {
public static void main(String[] args) {
JOptionPane.showMessageDialog(null, "Thử nghiệm Tiếng Việt", "Tiếng Việt", JOptionPane.INFORMATION_MESSAGE);
}
}


When compiling the source, be sure to specify the appropriate encoding:

javac -encoding utf8 NewMain.java
If the Unicode characters have been escaped (by native2ascii tool), no specification of encoding is necessary.

native2ascii -encoding utf8 NewMain.java NewMain.java
javac NewMain.java
java NewMain


If you run your program on a Java virtual machine (JVM) prior to Tiger (1.5 or 5.0), you will need to modify the font.properties file under the jre/lib directory to enable display of Vietnamese characters.

Followed is how to set the default file encoding to UTF-8 in common Java integrated development editors (IDE). Be sure to change the editor font to a Unicode font, such as Courier New, to enable display of Unicode characters in the source code.

エンコーディング - encoding(国際化/日本語化)

[S146-Q01]



String文字列をShift-JISや日本語EUCに変換したいのですが?


[S146-A01]
String#getBytes(String enc)を使用しましょう。
encに目的のエンコードを示す文字列を指定すると、指定したエンコードで変
換されたbyte配列が取得できます。

(例) Shift-JISのbyte配列を取得する。
String string = "テスト";
byte[] sjisBytes = string.getBytes("SJIS");

参考記事 [JavaHouse-Brewers:9873]



[S146-Q02]



Shift-JISや日本語EUCの文字列からStringを作るには?


[S146-A02]
new String(byte[] b, String enc)を使用しましょう。
Stringのコンストラクタで、bに文字列が格納されたバイト配列を、encにその
バイト配列の文字エンコーディングを指定すると、Stringオブジェクトが作ら
れます。

(例) Shift-JISのbyte配列からStringオブジェクトを生成する。
byte[] sjisBytes; // Shift-JISのbyte配列
String string = new String(sjisBytes, "SJIS");

参考記事 [JavaHouse-Brewers:9968]



[S146-Q03]



文字列を扱う要素が byte[], char[], String, StringBuffer などいろいろあ
るようですが、どう使い分けたら?


[S146-A03]
基本的に、次のように考えるとよいでしょう。
・byte[]…Unicode以外のエンコードの文字を1バイトづつ格納する配列。
・char[]…Unicode文字を1文字づつ格納する配列。
・String…Unicode文字列のRead Only表現
・StringBuffer…Unicode文字列操作のためのオブジェクト。

各要素間の変換で良く使われるものを挙げておきます。
・byte[]に文字コードを格納して、エンコーディング変換しながらStringに変

・Stringをエンコーディング変換してbyte[]に格納
・char[]にUnicode文字を格納してからStringに変換
・StringをStringBufferに変換し、StringBufferで文字列の結合、挿入などの
文字列操作を行ってからStringに変換

参考記事 [JavaHouse-Brewers:13287]



[S146-Q04]



デフォルトのエンコーディングを変えようとして、java -Dfile.encoding...
とオプションを変えてもうまく動きません。なぜ?


[S146-A04]
JDK1.2以降は、実行時にデフォルトのエンコーディングを変更する方法がない
ようです。
file.encoding プロパティを指定して java を起動しても無視されます。
現在、改善要求が
http://developer.java.sun.com/developer/bugParade/bugs/4175635.html
に登録されていますが、直されていません。

参考記事 [JavaHouse-Brewers:21272],[JavaHouse-Brewers:16640],[JavaHouse-Brewers:9141]



[S146-Q05]



Javaで指定できるエンコーディング名にはどのようなものが?


[S146-A05]
Sunが公開しているエンコーディング名一覧は、以下のURLで入手可能です。

JDK 1.1
http://www.javasoft.com/products/jdk/1.1/docs/guide/intl/encoding.doc.html

JDK 1.2
http://www.javasoft.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html

JDK 1.3
http://java.sun.com/j2se/1.3/docs/guide/intl/encoding.doc.html

指定可能なエンコーディング(より正確には、Unicodeと他のエンコーディング
とのコンバータ)の名前は、上記のURLで示されているものの他に、IANAで管理
されていたcharset名などもエイリアス(別名)として実現されています。

Sunが公開している上記のURLでは、エイリアスについて言及されていません。
エイリアスを含めた指定可能エンコーディング名一覧、関連情報については、
風間一洋氏が独自に解析し、以下のURLで公開しています.
http://www.ingrid.org/java/i18n/encoding/

なお、コンバータ名は大文字・小文字を区別しますが、エイリアス名はそれら
の区別をしないことに注意が必要です。



[S146-Q06]



Javaにおける文字コードの話で、時々「MS932」「CP932」「CP930」「CP939」
という言葉が出てきますが?


[S146-A06]
IBMやMicrosoftが定義したコードページ(文字集合の各要素に符号位置を割り
当てたもの)を識別する記号です。Javaでは、エンコーディング名として定義
されており、これらを用いて各コードページとUNICODEとの相互変換が可能で
す。

コンバータ名の中で、"MS"という接頭辞がついているものは、Microsoftの独
自仕様を示します。MicrosoftとIBMのコードページには、同じ番号でも相違点
があることがあり、その場合には、IBMはCP、MicrosoftはMSという接頭辞を番
号の前に付けて、コンバータを区別しているようです。



[S146-Q07]



Shift-JISや日本語EUCやJISの日本語コードを自動認識して読み込みたいのですが?


[S146-A07]
"JISAutoDetect"をエンコード指定することにより、ある程度の識別が可能です。
ただし、Shift-JISで書かれた'−'や'〜'などの文字を読み込む場合、
JDK1.1.8, JDK1.2以降のWindows環境とそれ以外のプラットフォームでは、
UNICODEへの変換方法に違いがあるので注意が必要です。

参考記事 [JavaHouse-Brewers:9995]



[S146-Q08]



デフォルトのエンコーディングがJISAutoDetectだと便利だと思うのですが、
そうなっていないのは何故?


[S146-A08]
JISAutoDetect は読み込み専用のエンコーディング名です。出力時に指定する
ことは許されていません。

JISAutoDetect は、JIS, Shift-JIS, 日本語EUCのいずれかのエンコーディン
グを自動識別して読み込み、Unicodeに変換します。出力時のエンコーディン
グを「自動識別」するという概念はないため、OutputStreamWriter などで
JISAutoDetect を指定すると UnsupportedEncodingException 例外が発生しま
す。

また、現在のJDKの実装では、デフォルトエンコーディング指定は入力と出力
とで同じものしか指定できないため、上記の理由により、JISAutoDetect はデ
フォルトエンコーディングに指定されていません。

参考記事 [JavaHouse-Brewers:12964],[JavaHouse-Brewers:13745]



[S146-Q09]



'−'や'〜'が文字化けします。他の文字は文字化けしていないのになぜ?


[S146-A09]
WindowsとUNIXなど、異なるプラットフォーム間でコンパイルや実行を行って
いませんか?
・日本語文字列を含むソースをコンパイルして、UNIXで実行(もしくは逆)
・WindowsとUNIX間での日本語文字列の受け渡し
上記のような振舞いによっては'−'や'〜'を始めとする一部の文字が正しく表
示されない現象が確認されています。

理由は、Windows環境のデフォルトコンバータである"MS932"(JDK1.1.8, 1.2以
降)と、その他の"JIS", "SJIS", "EUCJIS"とでは、同じ文字が異なるUNICODE
文字へマッピングされてしまうからです。

(例) '〜' をUNICODEへマッピングする場合
"JIS", "SJIS", "EUCJIS" を使用 → U+301C (WAVE DASH)
"MS932" を使用 → U+FF5E (FULLWIDTH TILDE)

このような文字を、一方のプラットフォームから他方へ受け渡して処理しよう
しても正しく処理されない可能性があります。
同様の理由で、MacOSと他のプラットフォームとでは、'…'の文字が影響を受
けます。

この問題はJDKのバージョン(JDK1.1.8, 1.2以降とそれ以外)によって挙動が
異なるため、注意が必要です。

この問題を根本的に解決する方法は今のところなく、正しい処理が行われるよ
うに、適時文字コード変換を行うしかありません。

この問題の対処法や詳しい情報は、風間一洋氏がJavaHouseメーリングリスト
上で公開した、文字コード変換フィルタ
http://java-house.etl.go.jp/ml/archive/j-h-b/014452.html
や、同氏のWebサイトにある「日本語のUnicodeベンダ依存文字表」
http://www.ingrid.org/java/i18n/unicode.html
を参考にしてください。

参考記事 [JavaHouse-Brewers:25058]



[S146-Q10]



JISAutoDetectで入力した元の漢字コードが何か知りたいのですが?


[S146-A10]
直接問題を解決できるAPIは用意されていませんが、Shift-JIS、JIS、日本語
EUC を指定して得られる3種類の String を、自動判別で得た String と比較
するという方法を使えば識別は可能です。

参考記事 [JavaHouse-Brewers:28949],[JavaHouse-Brewer:27372]



[S146-Q11]



MicrosoftのJavaで、エンコーディング名に"EUCJIS" を指定しても
UnsupportedEncodingException 例外が発生します。どうすれば?


[S146-A11]
MicrosoftのVMは、標準ではEUCをサポートしていません。追加パッケージのみ
の提供となっています。
http://www.microsoft.com/java/resource/misc.htm
"Additional I/O libraries" のリンクからたどれる ftp サイトから
sunio114.zip をダウンロードし、クラスパスに追加してください。
上記 ftp サイトで見つからない場合は以下の URL からダウンロードしてください。
ftp://ftp.sunet.se/pub3/vendor/microsoft/developr/MSDN/UnSup-ed/