我想检测一些文本的编码(使用PHP)。 为此,我使用mb_detect_encoding()函数。
问题是如果我用mb_detect_order()函数改变可能的编码顺序,函数会返回不同的结果。
考虑以下示例
$html = <<< STR
ちょっとのアクセスで落ちてしまったり、サーバー障害が多いレンタルサーバーを選ぶとあなたのビジネス等にかなりの影響がでてしまう可能性があります。特に商売をされている個人の方、法人の方は気をつけるようにしてください
STR;
mb_detect_order(array('UTF-8','EUC-JP', 'SJIS', 'eucJP-win', 'SJIS-win', 'JIS', 'ISO-2022-JP','ISO-8859-1','ISO-8859-2'));
$originalEncoding = mb_detect_encoding($str);
die($originalEncoding); // $originalEncoding = 'UTF-8'
但是,如果您更改mb_detect_order()中的编码顺序,结果将会有所不同:
mb_detect_order(array('EUC-JP','UTF-8', 'SJIS', 'eucJP-win', 'SJIS-win', 'JIS', 'ISO-2022-JP','ISO-8859-1','ISO-8859-2'));
die($originalEncoding); // $originalEncoding = 'EUC-JP'
所以我的问题是:
为什么会这样?
PHP中是否有正确无误地检测文本编码的方法?
答案 0 :(得分:5)
这就是我期望发生的事情。
检测算法可能只是按顺序继续尝试mb_detect_order
中指定的编码,然后返回字节流有效的第一个编码。
更智能的东西需要统计方法(我认为通常使用机器学习)。
编辑:参见例如this article用于更智能的方法。
由于其重要性,自动字符集检测已经在主要的Internet应用程序(如Mozilla或Internet Explorer)中实现。它们非常准确和快速,但实施在个案基础上应用了许多领域特定的知识。与他们的方法相反,我们的目标是一个简单的算法,可以统一应用于每个字符集,并且该算法基于完善的标准机器学习技术。我们还研究了语言和字符集检测之间的关系,并比较了基于字节的算法和基于字符的算法。我们使用朴素贝叶斯(NB)和支持向量机(SVM)。
答案 1 :(得分:5)
不是真的。不同的编码通常具有大的重叠区域,如果您测试的字符串在该重叠内部存在,则两种编码都是可接受的。
例如,utf-8和ISO-8859-1对于字母a-z是相同的。字符串“hello”在两种编码中都具有相同的字节序列。
这正是为什么首先有mb_detect_order()
函数的原因,因为它可以让你说出当这些冲突发生时你更喜欢发生什么。你想“你好”是utf-8还是ISO-8859-1?
答案 2 :(得分:2)
请记住mb_detect_encoding()
不知道数据的编码方式。您可能会看到一个字符串,但该函数本身只能看到一个字节流。除此之外,它需要猜测编码是什么 - 例如如果字节仅在0-127范围内,则为ASCII;如果存在ASCII字节,则为UTF-8,仅存在成对或更多字节的128+字节,等等。
可以想象,鉴于上下文,很难可靠地检测编码。
就像rihk所说的那样,这就是mb_detect_order()
函数的用途 - 您基本上是在猜测数据可能是什么。您经常使用UTF-8文件吗?那么即使mb_detect_encoding()
可能猜到它,你的东西很可能不会是UTF-16。
您可能还想查看Artefacto的link以获得更深入的视图。
示例案例:Internet Explorer使用一些有趣的编码猜测,如果没有指定任何内容(@link,章节:'自动检测网站的语言'),这会在网站上引起奇怪的行为编码过去是理所当然的。你可以找到一些有趣的东西,如果你谷歌周围。它是一个很好的展示案例,即使是统计方法也可以适得其反,以及为什么编码猜测通常会产生问题。
答案 3 :(得分:1)
mb_detect_encoding查看mb_detect_order()中的第一个charset条目,然后逐个循环输入$ html匹配字符,无论该字符是否属于charset的有效字符集。如果每个字符匹配,则返回true;如果任何字符失败,它将移动到mb_detect_order()中的下一个字符集并再次尝试。
The wikipedia list of charsets是查看构成每个字符集的字符的好地方。
因为这些字符集值重叠(char x8fA1EF存在于'UTF-8'和'EUC-JP'中),所以即使它在每个字符集中都是完全不同的字符,也会被视为匹配。因此,除非在一个字符集中存在任何字符值,而在另一个字符集中不存在,否则mb_detect_encoding无法识别哪个字符集无效;并将从您的数组列表中返回第一个可能有效的字符集。
据我所知,没有明确的方法来识别字符集。如果您对可能遇到的字符集有一个合理的了解,并根据每个字符集中的间隙(无效字符)相应地排序列表,那么PHP的“最佳猜测”方法可以得到帮助。 最好的解决方案是“了解”字符集。如果要从其他页面中抓取html,请在该页面的标题中查找charset标识符。
如果你真的想要聪明,你可以尝试识别编写html的语言,也许使用三元组或n-gram或类似PHP / ir上this article中描述的。