34491


Javaの文字コード変換についてネットを通して勉強中です。  
下記コード3行目でなぜ文字化けが発生してしまうかが分かりません。  
また文字化けしている変数を使っているのに「getBytes("ISO8859_1")」して「System.out.print(String.format("%02X
", (int)b & 0xff));」でコンソールの表示していますが「長所と短所」のSJISコード（92 B7 8F 8A 82 C6 92 5A 8F
8A）が表示され、処理が上手くいっているのか疑問です。

[code]

    public class Study {
    
        public static void main(String[] args) throws UnsupportedEncodingException {
    
            String original = "長所と短所";
            String stext = new String(original.getBytes("Shift-JIS"), "ISO8859_1");
            System.out.println("" + stext); // これは文字化け
            byte[]bytes = stext.getBytes("ISO8859_1"); // Shift-JISのコードを表示
            for (byte b: bytes) {
            System.out.print(String.format("%02X ", (int)b & 0xff));
            }
        }
    }
    
[/code]


CC BY-SA 3.0
2017-05-06T09:22:34.080
34483
2017-05-06T14:24:52.123
17348
question
java
Javaの文字コード変換の文字化けについて


`System.out`はデフォルトで`java.io.PrintStream`を指しており、`PrintStream#println`メソッドは与えられた`String`引数をデフォルトのエンコーディングで変換して出力するとあるので、`stext`が指す文字列をUnicode文字列として変換しているからではないでしょうか?  
(データをしては期待通りのものを保持しているが、出力時に変換がかかっている)


CC BY-SA 3.0
2017-05-06T10:35:47.887
34485
2017-05-06T10:35:47.887
20098
34483
answer


[UTF-8のファイルをSJISに変換後で文字化け。](https://ja.stackoverflow.com/q/34484/13972)の関連質問のようなので、こちらにも補足を書かせていただきます。

まずはあなたのコード中で`original.getBytes("Shift-
JIS")`というのは、元の文字列をShift_JISエンコーディングのバイト列に変換します。結果はあなたも書いておられますが、

>
[code]

>     92 B7 8F 8A 82 C6 92 5A 8F 8A
>  
[/code]

ですね。上記のコードを取り囲んでいる、`new String(...,
"ISO8859_1")`と言うのは、そのバイト列をISO-8859-1(通称ISO-
LATIN1)エンコーディングの文字列としてJavaの内部表現に変換します。

[ISO-8859-1](https://en.wikipedia.org/wiki/ISO/IEC_8859-1)

上記のバイト列をISO-8859-1の文字コード表にしたがって変換していくと、

>
[code]

>     92: <未定義の制御コード>
>     B7: · (欧文中点)
>     8F: <未定義の制御コード>
>     8A: <未定義の制御コード>
>     82: <未定義の制御コード>
>     C6: Æ (AとEのリガチャー)
>     5A: Z (普通のアルファベット大文字Z)
>     8F: <未定義の制御コード>
>     8A: <未定義の制御コード>
>  
[/code]

となります。

<未定義の制御コード>の部分はどんな表示になるか環境依存ということになりますが、それ以外の部分は上記の文字が表示されていないでしょうか。

次の`byte[]bytes =
stext.getBytes("ISO8859_1");`では`stext`の中身の文字列をISO-8859-1エンコーディングのバイト列に変換しています。これは先の`new
String(..., "ISO8859_1")`の逆操作ですから、その前のバイト列、つまり`original.getBytes("Shift-
JIS")`と同じ結果を返すのは当然、と言うことになります。

文字列の内部表現としてバイト列をそのまま格納するPHP(細かい違いはあるがPythonやRubyも同様)なんかでは、ISO-8859-1としてそのバイト列を解釈させることにより、1文字=1バイトになるので、中身の各バイトを取り出しやすくするためにISO-8859-1に変換するというのはよく知られたテクニックなのですが、それはJavaには通用しません。  
上記のような言語では、文字列処理として文字コード変換をした後、その文字列をそのままファイルに書き出せば文字コード変換が行われますが、Javaでは一旦Java文字列として正しく読み込まれたものに何らかのコード変換を行うようなことはせず、ファイルへの出力の際に出力文字コードを指定することで、文字コード変換を行わせます。(`System.out`は勝手にプラットフォームのデフォルト文字コードに変換してしまうので、そういう意味では文字コード変換結果の出力には使うべきではないでしょう。)

Java(その他C#やJavaScriptやObjective-
CやSwiftや…)とPHP系の文字列の取り扱いはそういう部分では大きく異なります。Javaでコーディングするのであれば、Java流に慣れてください。


CC BY-SA 3.0
2017-05-06T14:24:52.123
34491
2017-05-06T14:24:52.123
13972
34483
answer