如何检测非法 UTF-8 字节序列以在 java 输入流中替换它们?

Posted

技术标签:

【中文标题】如何检测非法 UTF-8 字节序列以在 java 输入流中替换它们?【英文标题】:How to detect illegal UTF-8 byte sequences to replace them in java inputstream? 【发布时间】:2011-04-17 15:27:27 【问题描述】:

有问题的文件不在我的控制之下。大多数字节序列都是有效的 UTF-8,它不是 ISO-8859-1(或其他编码)。 我想尽我所能提取尽可能多的信息。

文件包含一些非法的字节序列,应该用替换字符替换。

这不是一件容易的事,它认为它需要一些关于 UTF-8 状态机的知识。

Oracle 有一个包装器可以满足我的需要:UTF8ValidationFilter javadoc

是否有类似的东西可用(商业或免费软件)?

谢谢 -斯蒂芬

解决方案:

final BufferedInputStream in = new BufferedInputStream(istream);
final CharsetDecoder charsetDecoder = StandardCharsets.UTF_8.newDecoder();
charsetDecoder.onMalformedInput(CodingErrorAction.REPLACE);
charsetDecoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
final Reader inputReader = new InputStreamReader(in, charsetDecoder);

【问题讨论】:

我讨厌这个。内容生产者应该生产有效的内容,而不是要求消费者猜测和纠正。这给我们的行业带来了很多麻烦。 【参考方案1】:

java.nio.charset.CharsetDecoder 满足您的需求。此类提供字符集解码以及针对不同类型错误的用户可定义操作(请参阅onMalformedInput()onUnmappableCharacter())。

CharsetDecoder 写入OutputStream,您可以使用java.io.PipedOutputStream 将其通过管道传递到InputStream,从而有效地创建过滤的InputStream

【讨论】:

@Henning - 如果我想知道哪一行有坏字符怎么办? @Dejel 您可以将输入分成几行,并尝试每行检测错误。 是的,分割成行是可行的方法,但这通常是在 Reader 级别实现的,而不是在 InputStream 级别,因此您可能需要挖掘一下或自己编写。 【参考方案2】:

一种方法是读取前几个字节以检查字节顺序标记(如果存在)。有关 BOM 的更多信息:http://en.wikipedia.org/wiki/Byte_order_mark 在给定的 url 中,您将找到 BOM 字节表。但是,一个问题是,UTF-8 不需要在其标头中使用 BOM。还有另一种解决问题的方法是通过模式识别(每次读取几个字节 - 8 位)。无论如何,这是复杂的解决方案..

【讨论】:

问题不是 BOM,它已经被删除。有一个 BOMStripperInputStream 浮动,在这里有帮助:code.google.com/p/train-graph/source/browse/trunk/src/org/…【参考方案3】:

您想要的行为已经是InputStreamReader 的默认行为。所以不需要自己指定。这足够了:

final BufferedInputStream in = new BufferedInputStream(istream);
final Reader inputReader = new InputStreamReader(in, StandardCharsets.UTF_8);

【讨论】:

以上是关于如何检测非法 UTF-8 字节序列以在 java 输入流中替换它们?的主要内容,如果未能解决你的问题,请参考以下文章

如何修复 1 字节 UTF-8 序列的无效字节 1

如何在java中处理字节序列?

在 std::string 中使用非法 UTF-8 八位字节作为分隔符

java.lang.RuntimeException: org.dom4j.DocumentException: 1 字节的 UTF-8 序列的字节 1 无效。

如何在 PHP 中验证 utf 序列?

Python 3 时来自 BeautifulSoup 的“非法多字节序列”错误