我正在尝试使用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等)。
答案 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: ????��ǎ
这显示的是
?
Java(也是Groovy)在内部将字符存储为Unicode。 UTF16,确切地说。如果你想将它们编码为Ebcdic,那么它们将不再是字符,不应再保留在字符串中。 Ebcdic是一个8位编码,因此每个字符都可以存储在一个字节中。如果你需要与需要特定编码的系统(在你的情况下,Ebcdic)接口,那么该系统真的应该接受字节,而不是字符串,否则你最终只会遇到这些混乱。
如果必须使用字符串来保存Ebcdic字节,那么每当使用InputStream或OutputStream(包括System.out)时,必须使用ISO-8859-1编码,以确保您的ebcdic代码不会从字节“转换”到人物