【问题标题】:Unknown UTF-8 code units closing double quotes关闭双引号的未知 UTF-8 代码单元
【发布时间】:2013-01-17 12:28:05
【问题描述】:

我的问题如下。我正在阅读一个 XML 文件,其文本节点部分包含 UTF-8 版本的打开和关闭双引号。文本被提取,缩短为 3999 字节并放入新的 XML 格式,然后保存为文件。

虽然 Notepad++ 在输入文件中正确显示了这两个符号,但输出文件包含无效的 utf-8 字符,即使 Notepad++ 也无法显示。

开头的双引号打印正确,但结尾的双引号被毁容。

使用十六进制编辑器,我发现代码单元以某种方式更改

E2 80 9D

在输入文件中

E2 80 3F

在输出文件中。 我正在使用 sax-parser 进行 xml 解析。

是否有任何已知的错误可能导致这种行为?

【问题讨论】:

  • 您能否发布一个显示此行为的最小(但完整)程序,最好使用示例 XML 文件(可能托管在其他地方,因此我们可以获得确切的二进制数据) ?
  • 好吧,看来文件被解码为 Windows-1252。这可以解释结果,因为在 Windows-1252 中解码 e2 80 9d 输出为 e2 80 3f,其中 3f?9d 的替换字符在 Windows-1252 中未分配。

标签: java xml utf-8 saxparser


【解决方案1】:

不是一个已知的错误,而是在读取或写入文件时忽略编码的常见错误 - 导致使用的平台默认编码在这种情况下为 Windows-1252。

最初读取文件时,应指定 UTF-8 解码,写入新文件时,应指定 UTF-8 编码。如果你发布你的实现,我可以就地纠正它。

如何复制:

byte[] quoteutf8 = {(byte)0xE2, (byte)0x80, (byte)0x9D};
String decodedPlatformDefault = new String(quoteutf8, "Windows-1252");
byte[] encodedPlatformDefault = decodedPlatformDefault.getBytes("Windows-1252");

for( byte i : encodedPlatformDefault ) {
    System.out.print(String.format( "%02x ", i ));
   //e2 80 3f   
}

【讨论】:

    【解决方案2】:

    E2 80 9D 是 UTF-8 的有效字节序列,给出'”' = \u201d'。 您可以看到这一点,因为所有高位都已设置。 这是 UTF 值得称赞的安全属性,因此不会错误地在这样的序列中找到 ASCII,例如 '/'。

    在第二个序列中,3F ('?') 在字节中没有设置高位,所以是错误的。 这意味着读数出错(问号)左右。 就像转换两次,替换。尤其是 9D 在扩展的 Windows Latin-1 aka Cp1252 (80 - 9F) 中。

    【讨论】:

      【解决方案3】:

      从字节数组创建新字符串以及从字符串返回字节数组时,您应该始终指定字符集名称。

      如果没有,系统将采用默认字符集,可能会在各处造成问题...

      代替

      new String(myByteArray);
      //... and...
      myString.getBytes();
      

      你应该使用

      new String(myByteArray, "UTF-8");
      //... and...
      myString.getBytes("UTF-8");
      

      例如

      Transformer transformer = TransformerFactory.newInstance().newTransformer();
      
      transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
      
      StreamResult result = new StreamResult(new StringWriter());
      DOMSource source = new DOMSource(xmlDocument);
      transformer.transform(source, result);
      
      return result.getWriter().toString().getBytes("UTF-8");
      

      从 Java 1.6 开始,您可以specify a Charset 代替包含字符集名称的字符串:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-01-03
        • 2010-09-08
        • 1970-01-01
        • 2018-01-30
        • 2011-03-19
        • 2023-04-01
        • 1970-01-01
        相关资源
        最近更新 更多