Java中的Octal Escape导致错误的字节值,编码问题?

时间:2010-10-23 16:46:17

标签: java linux encoding utf-8

根据此文档(http://java.sun.com/docs/books/jls/third_edition/html/lexical.html,3.10.6),OctalEscape将转换为unicode字符。现在我遇到了问题,以下代码将导致带有错误信息的2字节Unicode字符。

for (byte b : "\222".getBytes()) {
     System.out.format("%02x ", b);
}

结果是“c2 92”。我只是表达“92”,因为这将是从222八进制到十六进制(92)的转换值。 如果我用一个字符测试它,字节信息是正确的。

System.out.format("%02x ", (byte)'\222');

一个字节的结果为“92” 我的默认编码是Linux上的“UTF-8”,带有Java / c 1.6.0_18。

我的问题的背景是,我正在寻找一种方法将八进制转义字符串从输入编码Cp1252转换为UTF-8。由于将八进制转义字符串转换为2个字节,因此失败。 有人知道为什么总是有一个额外的字节“c2”被添加到char数组?一个简单的计数显示,数组中只有一个字符。

System.out.println("\222".toCharArray().length); // will result in "1"

感谢您的提示。

更新: 正如BalusC所提到的,八进制转义值被解释为UTF-8值,从而产生问题。只要此值保存在源代码(UTF-8)中,我就无法使用其他编码读取此字符串。我是正确的?如果我读取Cp1252编码文件,我必须使用正确的字符集声明InputReader的字符集,并对UTF-8进行编码以处理并将读取的内容保存为UTF-8。

2 个答案:

答案 0 :(得分:4)

没有指定编码的String#getBytes()调用将使用平台默认编码将字符转换为字节。由于c2multibyte UTF-8 sequence的双字节字符的典型第一个字节,因此您显然使用UTF-8作为平台默认编码。如果要获得CP1252字节,则需要在String#getBytes(String charsetName)方法中明确指定。

for (byte b : "\222".getBytes("cp1252")) {
     System.out.format("%02x ", b);
}

根据您的更新

更新

  

只要此值保存在源代码(UTF-8)中,我就无法使用其他编码读入此字符串。我是正确的?

这是对的。您需要使用与保存文件相同的编码来读取文件,否则您可能会遇到mojibake的风险。

  

如果我读取Cp1252编码文件,我必须使用正确的字符集声明InputReader的字符集,并对UTF-8进行编码以处理并将读取的内容保存为UTF-8。

只需使用InputStreamReader将文件读取为CP1252即可。当读取为字符(字符串)时,Java将隐式存储为Unicode(UTF-16)。您可以将数据视为Unicode。没有必要引入中间UTF-8文件步骤。如果要保存文件,请将OutputStreamWriter与所需的字符集一起使用,这可能与CP1252不同。请记住,字符集未覆盖的任何字符最终都会显示为?

另见:

答案 1 :(得分:3)

Java中的所有字符和字符串都是UTF-16。因此,您已输入控制字符U+0092 PRIVATE USE TWO并将其编码为UTF-8(此字符在编码为UTF-8时占用两个字节)。编码为除UTF-16以外的任何字符的字符必须由字节数组表示。

U + 2019:'

我猜你打算对角色U+2019 RIGHT SINGLE QUOTATION MARK进行转码。在windows-1252中,它的字节值为92。我讨厌失望,但当编码为UTF-8时,这将最终成为多字节序列E2 80 99

另请注意,U + 2019不能用Java中的八进制转义序列表示,因为它的值大于U + 00FF。您必须使用Unicode转义序列\u2019。我写了一篇关于使用不同语言here进行转码并使用Java源文件here进行编码的博客文章。