~ To be, or not to be, or to ask someone to 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); } } 以上です。 余談:受信データの文字コード処理について†ほんとは最初にこの話題なのかもしれませんが、余談として... |
|