你看到这么多复杂的解决方案的原因是因为根据定义它是不可解决的。对文本字符串进行编码的过程是不确定的。可以构建产生相同字节流的文本和编码的不同组合。因此,从严格的逻辑上讲,不可能从字节流中确定编码、字符集和文本。
实际上,使用启发式方法可以获得“足够接近”的结果,因为您会在野外遇到一组有限的编码,并且通过足够大的样本,程序可以确定最可能的编码. 结果是否足够好取决于应用程序。
我确实想评论用户生成数据的问题。从网页发布的所有数据都具有已知的编码(POST 带有开发人员为页面定义的编码)。如果用户将文本粘贴到表单字段中,浏览器将根据源数据的编码(操作系统已知)和页面编码来解释文本,并在必要时对其进行转码。检测服务器上的编码为时已晚——因为浏览器可能已经根据假定的编码修改了字节流。
例如,如果我在德语键盘上键入字母 Ä 并将其发布到 UTF-8 编码的页面上,则将有 2 个字节 (xC3 x84) 发送到服务器。这是表示字母 C 和 d 的有效 EBCDIC 字符串。这也是一个有效的 ANSI 字符串,表示 2 个字符 Ã 和 „。但是,无论我如何尝试,都不可能将 ANSI 编码的字符串粘贴到浏览器表单中并期望它被解释为 UTF-8 - 因为操作系统知道我正在粘贴 ANSI(我复制了我在其中创建了一个 ANSI 编码的文本文件的 Textpad 中的文本)并将其转码为 UTF-8,从而生成字节流 xC3 x83 xE2 x80 x9E。
我的观点是,如果用户设法发布垃圾,可以说是因为它在粘贴到浏览器表单时已经是垃圾,因为客户端没有对字符集、编码等任何适当的支持。因为字符编码是不确定的,所以你不能指望有一种简单的方法可以从这种情况中发现。
不幸的是,对于上传的文件,问题仍然存在。我看到的唯一可靠的解决方案是向用户显示文件的一部分并询问它是否被正确解释,并循环通过一堆不同的编码,直到出现这种情况。
或者我们可以开发一种启发式方法来查看某些字符在各种语言中的出现。假设我上传了包含两个字节 xC3 x84 的文本文件。没有其他信息 - 文件中只有两个字节。这种方法可以发现字母 Ä 在德语文本中相当常见,但字母 Ã 和 „ 一起在任何语言中都不常见,从而确定我的文件的编码确实是 UTF-8。这种粗略是这种启发式方法必须处理的复杂程度,它可以使用的统计和语言事实越多,其结果就越可靠。