文字を化けさせる
iアプリをAndrod上で動作させるため、
SJIS(Shift_JS)のテキストファイルを読み込もうとしている。
しかしこれには文字化けの問題がある。
Androidは一旦置いとく。
実験
SJISのテキストファイルをつくる
まず元となるテキストファイルを用意する。
文字コードはutf-8
とした。
hoge.txt
アンドロイド☆イズ☆デッド
このファイルの文字コードをSJIS
に変更する。
% iconv -f utf-8 -t sjis hoge.txt > hoge.sjis.txt
UTF-8で読み込む
InputStreamReader
に文字コードを指定する。
指定しないとデフォルトの文字コードを使う。
Androidも(キミのmacも)デフォルトはutf-8
だ。
FileInputStream is = new FileInputStream("hoge.sjis.txt");
InputStreamReader isr = new InputStreamReader(is/*, "utf-8"*/);
BufferedReader reader = new BufferedReader(isr);
String line = reader.readLine();
System.out.println("line: "+bytesToHex(line.getBytes(/*"utf-8"*/)));
bytesToHex(byte[]) http://stackoverflow.com/a/9855338
実験結果
line: EFBFBD41EFBFBDEFBFBDEFBFBD68EFBFBDEFBFBDEFBFBD43EFBFBD68EFBFBDEFBFBDEFBFBD43EFBFBD59EFBFBDEFBFBDEFBFBD66EFBFBD62EFBFBD68
もちろんこんなString line
をそのままUTF-8文字として出力しても
文字化けして読めないんだけど、
そのバイト列としても、なんだかおおよそ文字とは思えないものがでてくる。
なんだこれは。
もとの文字列のバイト列とくらべてみよう。
% hexdump hoge.sjis.txt
の出力は
0000000 83 41 83 93 83 68 83 8d 83 43 83 68 81 99 83 43
0000010 83 59 81 99 83 66 83 62 83 68 0a
000001b
である。やっぱぜんぜん違う感じする。
utf-8
として読み込んだ文字列のバイト列には
EFBFBD
というものが繰り返し出現することがわかる。
これを**
に置き換えて整形すると……
0000000 ** 41 ** ** ** 68 ** ** ** 43 ** 68 ** ** ** 43
0000010 ** 59 ** ** ** 66 ** 62 ** 68
似ている。
考察
InputStreamReader
がhoge.sjis.txt
の内容を読むときに、
utf-8
の文字が来ると期待するため、
その範疇にない文字を「表現できない文字」として
EFBFBD
に置き換えてしまっている。
JavaのString
になった時点で、元の情報を失う。
結論
InputStreamReader
で文字化けしたStringを、元のbyte列に戻すことはできない。
それゆえ、他の文字コードに変換することもできない。
iアプリとAndroid
iアプリではデフォルトの文字コードがSJIS
だった。
Androidではutf-8
。
だから、
new InputStreamReader(is);
とか、
"いやまずiアプリって何".getBytes();
とかやったときに使われる文字コードが
iアプリとAndroidで異なる。