問題は次の式にあります。
new String(letters.getBytes('IBM500'))
letters.getBytes は、以下を含むバイト配列を作成します (16 進数):
81 82 83 84 C1 C2 C3 C4
しかし、プラットフォームのデフォルトのエンコーディングを使用して、すぐにそれを Unicode 文字列に変換しています。
new String( <byte-array> );
String 内の文字の序数値をバイト値と等しくしたい場合は、ISO-8859-1 など、それを行うエンコーディングを指定する必要があります。
new String(letters.getBytes('IBM500'), "ISO-8859-1")
使用しているエンコーディングでは、バイトの文字エンコーディングが定義されていないため、( )81
に置き換えられ ます。Windows-1252を使用している可能性が最も高いです。?
3f
文字列には、バイトではなく文字が含まれます。Java は、一方から他方に移動するときに常にエンコード変換を適用します。
編集:@ミスター270のコメントへの応答:
デモ用の Java のプログラムを次に示します。
public class Ebcdic
{
public static void main(String[] args) throws Exception
{
String letters = "abcdABCD";
byte[] ebcdic = letters.getBytes("IBM500");
System.out.print("Ebcdic bytes:");
for (byte b: ebcdic)
{
System.out.format(" %02X", b & 0xFF);
}
System.out.println();
String lettersEbcdic = new String(ebcdic, "ISO-8859-1");
System.out.print("Ebcdic bytes stored in chars:");
for (char c: lettersEbcdic.toCharArray())
{
System.out.format(" %04X", (int) c);
}
System.out.println();
System.out.println("Ebcdic bytes in chars printed in using my default platform encoding: " + lettersEbcdic);
}
}
出力は次のとおりです。
Ebcdic bytes: 81 82 83 84 C1 C2 C3 C4
Ebcdic bytes stored in chars: 0081 0082 0083 0084 00C1 00C2 00C3 00C4
Ebcdic bytes in chars printed in using my default platform encoding: ????��ǎ
これが示していることは、
- 「IBM500」を使用して、バイト配列への Ebcdic 変換が正しく行われている
- 「ISO-8859-1」を使用したバイトから文字への「ID」変換が正しく行われている
- 私のシステムには、Unicode 文字 U+0081 などをデフォルトのプラットフォーム文字エンコーディングに変換するためのマッピングがないため、次のように表示されます。
?
Java (Groovy も同様) は、文字を内部的に Unicode として格納します。正確にはUTF16です。それらを Ebcdic としてエンコードする場合、それらは文字ではなくなり、文字列に保持されなくなります。Ebcdic は 8 ビット エンコーディングであるため、各文字を 1 バイトに格納できます。特定のエンコーディング(あなたの場合はEbcdic)を期待するシステムとインターフェースする必要がある場合、そのシステムは文字列ではなくバイトを実際に受け入れる必要があります。そうしないと、このような混乱が発生します。
Strings を使用して Ebcdic バイトを保持する必要がある場合は、InputStream または OutputStream (System.out を含む) を使用するときは常に ISO-8859-1 エンコーディングを使用して、ebcdic コードがバイトから文字に「変換」されないようにする必要があります。