|
~ To be, or not to be, or to let it be. ~ null-i.net |
| AndroidJava/文字コード、文字化けの対応 | |
|
文字コード、文字化けの対応(2019-12-06) Android、というよりはJavaの話題になると思います。 はじめに、基本的な例†以下、文字コードを指定して @Test
public void test(){
example1(); // 詳細は6行ほど後で、
}
private void log(String string){ // ただのプリント文です。
System.out.println(string); // 必要に応じてここを Log.d などに置き換えて下さい。
}
private void example1(){
String text_org = "はろー"; // オリジナルの文字列
byte[] b_array;
String[] from_codecs = {"UTF-8", "Shift_JIS"};
String to_code = "UTF-8"; // from_code と異なる文字コードを指定
for(String from_code : from_codecs) {
try { // String -> byte[] -> String に変換する
b_array = text_org.getBytes(from_code);
String text_after = new String(b_array, to_code);
log("code:" + from_code + "->" + to_code + ", byte-length:" + b_array.length + ", text:" + text_after);
} catch (Exception e) {
log("Exception:" + e);
}
}
}
(実行イメージ) code:UTF-8->UTF-8, byte-length:9, text:はろー code:Shift_JIS->UTF-8, byte-length:6, text:??[ 1つめは変換してもとに戻す、2つめは文字コード不一致で文字化けする例です。 文字化けを確認したり情報を得たりする例†前の例では日本語テキスト全体を変換しましたが、 // 前述の example1 をコレに置き換えて下さい。
private void example2(){
String text_org = "はろー"; // オリジナルの文字列
byte[] b_array;
ByteBuffer b_buff; // これは CharsetDecoder で使います
CharBuffer c_buff = CharBuffer.allocate(128); // これも CharsetDecoder で使います。128は、よしなに
String from_code ="UTF-8";
String to_code = "UTF-8";
try { // try で getBytes()と new String() の例外を拾う、が、手抜きしてfor文ごとまるまるtryしています
b_array = text_org.getBytes(from_code);
for(int i=1; i<=b_array.length; i++){ // 1バイトずつ読み込む範囲を広げる
byte[] buffer = new byte[i];
System.arraycopy(b_array, 0, buffer, 0, i);
String text_after = new String(buffer, to_code);
log("---\ncode:" + from_code + "->" + to_code + ", byte-length:" + buffer.length + ", text:" + text_after);
// 以下、CharsetDecoder を使う例
CharsetDecoder dec = Charset.forName(to_code).newDecoder();
dec.onUnmappableCharacter(CodingErrorAction.REPORT);
dec.onMalformedInput(CodingErrorAction.REPORT);
//--REPORTではなく、CodingErrorAction.REPLACE なら置き換えたい文字を指定--
// dec.replaceWith("#");
b_buff = ByteBuffer.wrap(b_array, 0, i);
c_buff.clear();
CoderResult coderResult = dec.decode(b_buff, c_buff, true);
c_buff.flip();
// CodingErrorAction.REPORT を指定した場合は情報を得られます
if(coderResult.isMalformed() || coderResult.isUnmappable()){
log("isMalformed:" + coderResult.isMalformed() + ", isUnmappable:" + coderResult.isUnmappable()
+ ", position:" + b_buff.position()
+ ", length:" + coderResult.length());
}
// REPLACE と replaceWith() を使った場合は置き換え文字が指定できます
// log("dec_text:" + c_buff.toString());
}
} catch (Exception e) {
log("Exception:" + e);
}
}
(実行イメージ) --- code:UTF-8->UTF-8, byte-length:1, text:? isMalformed:true, isUnmappable:false, position:0, length:1 --- code:UTF-8->UTF-8, byte-length:2, text:? isMalformed:true, isUnmappable:false, position:0, length:2 --- code:UTF-8->UTF-8, byte-length:3, text:は --- (以下、省略) CharBuffer の扱い方(flipやclear)については、それだけで1ページ必要なのでここでは省略させてください。
文字コードの件に戻って、 private void example3(){
String from_code ="UTF-8";
String to_code = "UTF-8";
String text_org1 = "はろー"; // オリジナルの文字列
String text_org2 = "ワールド"; // オリジナルの文字列
byte[] buffer;
//byte[] b_middle = new byte[]{ (byte)0x1b }; // ESC(=0x1b)。ふつうに印字不可文字として扱われるはず
//byte[] b_middle = new byte[]{ (byte)0x0a }; // 改行(=0x0a)。ふつうに改行が発生するだけ。
byte[] b_middle = new byte[]{ (byte)0xa0 }; // 文字化けの場合の例、何らかの処理が必要
// テスト用に特殊な文字列を生成する
try {
byte[] b_array1 = text_org1.getBytes(from_code);
byte[] b_array2 = text_org2.getBytes(from_code);
buffer = new byte[b_array1.length + b_middle.length + b_array2.length];
int n = 0;
System.arraycopy(b_array1, 0, buffer, n, b_array1.length); n += b_array1.length;
System.arraycopy(b_middle, 0, buffer, n, b_middle.length); n += b_middle.length;
System.arraycopy(b_array2, 0, buffer, n, b_array2.length);
} catch (Exception e){
log("Exception:" + e);
return;
}
ByteBuffer b_buff;
CharBuffer c_buff = CharBuffer.allocate(128); // 十分な値を指定すること。
try {
String text_after = new String(buffer, to_code);
log("---\ncode:" + from_code + "->" + to_code + ", byte-length:" + buffer.length + ", text:" + text_after);
// 文字化けしている箇所を特定したり、置き換え文字を指定したりする場合は CharsetDecoder を使う
CharsetDecoder dec = Charset.forName(to_code).newDecoder();
dec.onUnmappableCharacter(CodingErrorAction.REPORT);
dec.onMalformedInput(CodingErrorAction.REPORT);
//--REPORTではなく、CodingErrorAction.REPLACE なら置き換えたい文字を指定--
// dec.replaceWith("#");
b_buff = ByteBuffer.wrap(buffer);
c_buff.clear();
CoderResult coderResult = dec.decode(b_buff, c_buff, true);
c_buff.flip();
// CodingErrorAction.REPORT を指定した場合は情報を得られます
if(coderResult.isMalformed() || coderResult.isUnmappable()){
log("isMalformed:" + coderResult.isMalformed() + ", isUnmappable:" + coderResult.isUnmappable()
+ ", position:" + b_buff.position()
+ ", length:" + coderResult.length());
}
// REPLACE と replaceWith() を使った場合は置き換え文字が指定できます
// log("dec_text:" + c_buff.toString());
} catch (Exception e) {
log("Exception:" + e);
}
}
以上です。 余談:受信データの文字コード処理について†ほんとは最初にこの話題なのかもしれませんが、余談として... |
|