前述のように、Javaは内部的に文字エンコーディングとしてUTF-16を用いています。このUTF-16をほかの文字エンコーディングに変換するための機能がJava APIとして提供されています。世の中にあるさまざまな文字エンコーディングを取り扱うために、この機能は必要になります。
まず、バイト配列を一般的な16進表記文字列にするためのユーティリティクラス(HexStringUtil.java)を準備しておきます。
public final class HexStringUtil { |
これ以降のソースコードは、このユーティリティクラスが存在することを前提としています。なお、このようなユーティリティは文字コードを調べる目的以外でも有益である場合があります。ぜひご活用ください。
最初に、日本語の文字エンコーディングとしてよく用いられているシフトJISの文字エンコーディングを調べます。Java上の文字列をシフトJISのバイト配列に変換する例を見てみましょう。
|
実行すると、下記のような結果を取得できます。
[愛植岡]をシフトJISのバイト配列に変換
88 a4 90 41 89 aa
この例では3文字が6個のbyteへと変換されていることが分かります。ただこれでは、どの文字がどの文字に変換されたのか分からないので、1文字だけ変換してみます。上記ソースコード中の桃色の個所を下記のように書き換えます。
new StringToBytesSample().process("愛"); |
すると、‘愛’の文字が88 a4 という2バイトへと変換されることが分かります。
[愛]をシフトJISのバイト配列に変換
88 a4
これとは逆に、バイト配列から文字列を作ることができます。今回得られたバイト配列を下記ソースコード中の桃色の個所のように与えて、文字列へと変換します。
import java.io.UnsupportedEncodingException; |
実行結果は下記のようになります。元の文字列に戻っていることが分かります。
[88 a4 90 41 89 aa]をシフトJISのバイト配列として文字列に変換
愛植岡
文字列とバイト配列の相互変換は、下記のような対応になります。
それでは、シフトJIS以外の文字エンコーディングも調べていきます。まず、簡単に文字エンコーディングを切り替えられるように、先ほどのStringToBytesSample.javaのソースコードを少し拡張し、文字エンコーディング指定を外部から変更できるようにしておきます。
import java.io.UnsupportedEncodingException; |
準備ができたので、サンプルプログラムを動作させてみましょう。私たちはプログラマーなので、こういった事象をプログラムを使って検証できます。
まず、UNIXなどで日本語を扱う際によく使われているEUC-JPエンコーディングを指定して動作させてみます。
new StringToBytesSampleEnc().process("愛植岡", "EUC-JP"); |
[愛植岡]を[EUC-JP]バイト配列に変換
b0 a6 bf a2 b2 ac
ここで指定できる文字列は 前述のサポートされているエンコーディングのページで調べることができます。EUC-JP以外にも、よく知られる文字エンコーディングを与えてみましょう。
[愛植岡]を[ISO-2022-JP]バイト配列に変換
1b 24 42 30 26 3f 22 32 2c 1b 28 42
エスケープシーケンスと呼ばれるものが付与されているため、かなりバイト数が増えます。エスケープシーケンスについての詳細は、『文字コード超研究』の316ページなどを参照ください。
特に、XMLなどにおいて頻繁に利用されるのが、UTF-8エンコーディングです。UTF-8はUnicodeの文字エンコーディングのひとつです。
[愛植岡]を[UTF-8]バイト配列に変換
e6 84 9b e6 a4 8d e5 b2 a1
同じく、XMLなどにおいてよく利用されるのが、UTF-16エンコーディングです。UTF-16はUnicodeの文字エンコーディングのひとつです。
UTF-16エンコーディングはバイト配列表現に変換する際に注意が必要になります。というのも、16ビットであるchar型を8ビットであるbyte型に詰め込む際に、上位8ビットと下位8ビットのいずれのbyteを配列として先に位置させるのか(エンディアン)を明示する必要があるからです。
UTF-16BEはビッグエンディアン(big endian)を明示したUTF-16です。上位8ビットの方が先に配置されます(先ほど‘愛’は611bだったことを思い出してください)。
[愛植岡]を[UTF-16BE]バイト配列に変換
61 1b 69 0d 5c a1
UTF-16LEはリトルエンディアン(little endian)を明示したUTF-16です。下位8ビットの方が先に配置されます。
[愛植岡]を[UTF-16LE]バイト配列に変換
1b 61 0d 69 a1 5c
UTF-16はエンディアンを明示していません。その代わり、先頭に「バイト順マーク(BOM:Byte Order Mark)」というものを2バイト付与してエンディアンを表現します。この2バイトでリトルエンディアンかビッグエンディアンかを判断できるようになっています。
[愛植岡]を[UTF-16]バイト配列に変換
fe ff 61 1b 69 0d 5c a1
なお、この実行例はビッグエンディアンです。リトルエンディアンの際には、先頭にff fe の2バイトが付与されます。
ここでもし、Javaでサポートされていない文字エンコーディングを指定すると、例外が発生します。例えば、存在しない名称の“ARIMASEN”エンコーディングを指定してみて動作させてください。下記のような例外が発生します。
[愛植岡]を[ARIMASEN]バイト配列に変換
サポートされないエンコーディング[ARIMASEN]が指定されました。
java.io.UnsupportedEncodingException: ARIMASEN
at sun.io.Converters.getConverterClass(Unknown Source)
at sun.io.Converters.newConverter(Unknown Source)
at sun.io.CharToByteConverter.getConverter(Unknown Source)
at java.lang.StringCoding.encode(Unknown Source)
at java.lang.String.getBytes(Unknown Source)
at StringToBytesSampleEnc.process(StringToBytesSampleEnc.java:18)
at StringToBytesSampleEnc.main(StringToBytesSampleEnc.java:6)
このように、文字エンコーディング名は少しでも間違えると、サポートしないエンコーディング名を指定したことになり、例外が発生します。
Copyright © ITmedia, Inc. All Rights Reserved.