EBCDIC代码页不转换小写'a'

时间:2013-05-20 23:27:15

标签: groovy character-encoding ebcdic

我正在尝试使用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”。尽量尝试我找不到有关此问题的任何信息。我尝试了许多具有相同结果的IBM代码页(IBM01140,IBM1047等)。

1 个答案:

答案 0 :(得分:3)

问题在于这个表达式:

new String(letters.getBytes('IBM500'))

letters.getBytes创建一个包含(十六进制)的字节数组:

 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的字符编码,因此它将替换为?3f)。您最有可能使用Windows-1252

字符串包含字符,而不是字节。当从一个转到另一个时,Java将始终应用编码转换。

编辑:回复@ mister270的评论:

这是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”将字节“字符”转换为字符
  • 我的系统没有将Unicode字符U + 0081等转换为我的默认平台字符编码的映射,因此它将其显示为?

Java(也是Groovy)在内部将字符存储为Unicode。 UTF16,确切地说。如果你想将它们编码为Ebcdic,那么它们将不再是字符,不应再保留在字符串中。 Ebcdic是一个8位编码,因此每个字符都可以存储在一个字节中。如果你需要与需要特定编码的系统(在你的情况下,Ebcdic)接口,那么该系统真的应该接受字节,而不是字符串,否则你最终只会遇到这些混乱。

如果必须使用字符串来保存Ebcdic字节,那么每当使用InputStream或OutputStream(包括System.out)时,必须使用ISO-8859-1编码,以确保您的ebcdic代码不会从字节“转换”到人物