我做了以下“模拟”:
byte[] b = new byte[256];
for (int i = 0; i < 256; i ++) {
b[i] = (byte) (i - 128);
}
byte[] transformed = new String(b, "cp1251").getBytes("cp1251");
for (int i = 0; i < b.length; i ++) {
if (b[i] != transformed[i]) {
System.out.println("Wrong : " + i);
}
}
对于cp1251
,这只输出一个错误的字节 - 位置25
对于KOI8-R
- 一切都很好。
对于cp1252
- 4或5个差异。
这是什么原因以及如何克服这个原因?
我知道错误将字节数组表示为任何编码的字符串,但这是付款提供商协议的要求,所以我没有选择。
在ISO-8859-1
中表示 更新:,我会将其用于byte[]
部分,将cp1251
用于文字部分,因此问题仍然只是出于好奇而
答案 0 :(得分:11)
目标集中不支持某些“字节” - 它们将替换为?
字符。转换回来时,?
通常会转换为字节值63 - 这与以前不同。
答案 1 :(得分:7)
这是什么原因
原因是字符编码不一定是bijective,并且没有充分的理由期望它们。并非所有字节或字节序列在所有编码中都是合法的,并且通常非法序列被解码为某种占位符字符,如“?”或U+FFFD,当然在重新编码时不会产生相同的字节。
此外,某些编码可能会将一些合法的不同字节序列映射到同一个字符串。
答案 2 :(得分:4)
看来cp1251和cp1252的字节值都与定义的字符不对应;即它们是“不可映射的”。
String(byte[], String)
的javadoc说:
未指定给定字节在给定字符集中无效时此构造方法的行为。当需要更多地控制解码过程时,应该使用
CharsetDecoder
类。
其他建设者说:
此方法始终使用此charset的默认替换字符串替换格式错误的输入和不可映射字符序列。
如果你在实践中看到这种事情发生,它表明你使用了错误的字符集,或者你被给了一些不好的数据。无论哪种方式,继续进行可能不是一个好主意,好像没有问题。
我一直试图弄清楚是否有办法让CharsetDecoder“保留”不可映射的字符,除非你愿意实现自定义解码器/编码器对,否则我认为不可能。但我也得出结论,即使尝试也没有意义。它(理论上)错误地将那些不可映射的字符映射到真正的Unicode代码点。如果你这样做,你的应用程序将如何处理它们?
答案 3 :(得分:3)
实际上应该有一个区别:值24的字节转换为值char
的{{1}};这是“Unicode替换字符”,用于不可翻译的字节。转换回来时,会得到一个问号(值63)。
在CP1251中,代码24表示“输入结束”,不能成为正确字符串的一部分,这就是为什么Java认为它是“不可翻译的”。
答案 4 :(得分:2)
历史原因:在古代字符编码(EBCDIC,ASCII)中,前32个代码具有特殊的“控制”含义,它们可能不会映射到可读字符。示例:退格,铃声,回车。较新的字符编码标准通常会继承这一点,并且它们不会为前32个位置中的每一个定义Unicode字符。 Java字符是Unicode。