3

IBM コードページを使用して、文字列を ASCII から EBCDIC に変換しようとしています。印刷できない文字に変換される小文字の 'a' を除いて、変換は正しく行われます。

これは、Windows 7 で実行されている groovy スクリプトの一部で、問題を示しています。

groovy:000> letters='abcdABCD'
===> abcdABCD
groovy:000> String.format("%04x", new BigInteger(1, letters.getBytes())
===> 6162636441424344
groovy:000> lettersx=new String(letters.getBytes('IBM500'))
===> ?éâä┴┬├─
groovy:000> String.format("%04x", new BigInteger(1, lettersx.getBytes()))
===> 3f828384c1c2c3c4

EBCDIC に変換すると、最初の小文字の「a」を除いて、文字列内のすべての文字が有効になります。この問題に関する情報が見つかりません。同じ結果 (IBM01140、IBM1047 など) で多数の IBM コード ページを試しました。

4

1 に答える 1

3

問題は次の式にあります。

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 コードがバイトから文字に「変換」されないようにする必要があります。

于 2013-05-20T23:45:14.480 に答える