___编码为UTF-8 - 是否存在最终解决方案?

时间:2010-06-11 21:01:57

标签: php utf-8 character-encoding special-characters iso-8859-1

我浏览了网页,我通过PHP文档等了解了这些内容。

这似乎是一个荒谬的问题,没有标准的解决方案。如果你得到一个未知的字符集,并且它有奇怪的字符(如英语引号),是否有标准方法将它们转换为UTF-8?

我已经看到许多使用大量功能和检查的混乱解决方案,但它们都不会发挥作用。

有没有人提出自己的功能或总是有效的解决方案?


修改

很多人都回答说“这是不可解决的”或类似的东西。我现在明白了,但除了utf8_encode之外,没有人提供任何有效的解决方案。有什么方法可以解决这个问题?什么是 最佳 方法?

4 个答案:

答案 0 :(得分:11)

没有。人们应该总是知道字符串是什么字符集。使用嗅探函数猜测字符集是不可靠的(尽管在大多数情况下,在西方世界,它通常是ISO-8859-1和UTF-8之间的混淆)。

但为什么你要处理未知的字符集呢?对此没有通用的解决方案,因为一般问题不应该存在。每个网页和数据源都可以并且应该有一个字符集定义,如果没有,则应该请求该资源的管理员添加一个。

(听起来不像是智能手机,但 是解决这个问题的唯一方法。)

答案 1 :(得分:9)

你为这个问题看到这么多复杂的解决方案的原因是因为根据定义它是不可解决的。编码一串文本的过程是非确定性的。 可以构造导致相同字节流的文本和编码的不同组合。因此,从逻辑上讲,从字节流中确定编码,字符集和文本是不可能的。

实际上,有可能使用启发式方法获得“足够接近”的结果,因为您将在野外遇到一组有限的编码,并且如果有足够大的样本,程序可以确定最有可能的编码。结果是否足够好取决于应用程序。

我想对用户生成数据的问题发表评论。从网页发布的所有数据都具有已知编码(POST附带开发人员为页面定义的编码)。如果用户将文本粘贴到表单字段中,则浏览器将基于源数据的编码(如操作系统所知)和页面编码来解释文本,并在必要时对其进行转码。检测服务器上的编码为时已晚 - 因为浏览器可能已根据假定的编码修改了字节流。

例如,如果我在德语键盘上键入字母Ä并将其发布在UTF-8编码页面上,则会有2个字节(xC3 x84)发送到服务器。这是一个有效的EBCDIC字符串,表示字母C和d。这也是一个有效的ANSI字符串,代表2个字符Ã和“。但是,无论我尝试什么,都不可能将ANSI编码的字符串粘贴到浏览器表单中并期望它被解释为UTF-8 - 因为操作系统知道我粘贴了ANSI(我复制了来自Textpad的文本,我在其中创建了一个ANSI编码的文本文件),并将其转码为UTF-8,从而产生字节流xC3 x83 xE2 x80 x9E。

我的观点是,如果用户设法发布垃圾,可以说是因为它被粘贴到浏览器表单时已经是垃圾,因为客户端没有对字符集的正确支持,编码, 随你。 因为字符编码是非确定性的,所以你不能指望存在一种从这种情况中发现的简单方法。

不幸的是,对于上传的文件,问题仍然存在。我看到的唯一可靠的解决方案是向用户显示文件的一部分并询问它是否被正确解释,并循环执行一系列不同的编码,直到出现这种情况。

或者我们可以开发一种启发式方法,查看各种语言中某些字符的出现。假设我上传了包含两个字节xC3 x84的文本文件。没有其他信息 - 文件中只有两个字节。这种方法可以发现字母Ä在德语文本中相当常见,但字母Ã和“在一起并不常见于任何语言,因此确定我的文件的编码确实是UTF-8。这种粗糙是这种启发式方法必须处理的复杂程度,它可以使用的统计和语言事实越多,其结果就越可靠。

答案 2 :(得分:1)

Pekka对于不可靠性是正确的,但是如果你需要一个解决方案并且愿意承担风险,并且你有mbstring库可用,那么这个代码片段应该可以工作:

function forceToUtf8($string) {
    if (!mb_check_encoding($string)) {
        return false;
    }
    return mb_convert_encoding($string, 'UTF-8', mb_detect_encoding($string));
} 

答案 3 :(得分:0)

如果我没错,那就有一个名为utf8encode的东西...除非你已经在utf8中,否则效果很好

http://php.net/manual/en/function.utf8-encode.php