4

首先,我想说我已经阅读了关于 PHP 的 mb_detect_encoding 的另一篇文章, 位于 PHP 中 mb_detect_order() 的奇怪行为。这肯定会再次确认我会通过跟踪和错误学到什么。但是仍然有一些事情让我感到困惑。

我正在构建一个主要是英文网站的 html 抓取工具,用于收集数据并将其存储到 UTF-8 XML 中。我遇到了一个问题,页面自身声明了 ISO-8859-1 字符集,但它包含 Windows-1252 独有的字符。特别是右单引号 (') 0x92。据我了解,windows-1252 是 iso-8859-1 的超集,这促使我思考为什么要费心使用 utf8_encode() 呢?为什么不直接使用 iconv('Windows-1252', 'UTF-8', $str) 代替 utf8_encode() ,因为 iso-8859-1 中表示的任何内容以及 windows-1252 独有的字符都会被转换(即€‚ƒ''“”)

$ansi = "€";//euro mark, the code file itself is in ansi

$detected = mb_detect_encoding($ansi, "WINDOWS-1252");// $detected == "Windows-1252"
$detected = mb_detect_encoding('a'.$ansi, "WINDOWS-1252");// $detected == FALSE
$detected = mb_detect_encoding($ansi.'a', "WINDOWS-1252");// $detected == "Windows-1252"
$detected = mb_detect_encoding($ansi.'a', "WINDOWS-1252",TRUE);// $detected == FALSE

为什么会这样?如果字符串中的第一个字符不是 windows-1252,即使它的其余部分是,它也会失败?这种行为不是让它变得毫无用处吗?至于区分 iso-8859-1 和 windows-1252

让我感到困惑的另一件事是,假设我想检测 ASCII、ISO-8859-1、windows-1252、UTF-8 之间的字符集。是否有可能以使我获得最低排名的方式检测字符串?(IE。

$ascii = "123"; // desired detect result == 'ASCII'
$iso = "é".$ascii; // desired detect result == 'ISO-8859-1'
$ansi = "€".$iso; // desired detect result == 'Windows-1252'
$utf8 = file_get_contents('utf8.txt', true);//$utf8 == '你好123é€', desired detect result == 'UTF-8'

我的 $detect_order = array('ASCII', 'ISO-8859-1', 'Windows-1252','UTF-8'); 我知道这是不正确的,因为它给了我以下结果

$ascii == 'ASCII'
$iso   == 'ISO-8859-1'
$ansi  == 'ISO-8859-1'
$utf8  == 'ISO-8859-1'

为什么我的 ('ASCII', 'ISO-8859-1', 'Windows-1252','UTF-8') 的检测顺序对于我想要得到的东西是错误的?

我得到的最接近的期望返回值是

$ascii == 'ASCII'
$iso   == 'ISO-8859-1'
$ansi  == 'ISO-8859-1'
$utf8  == 'UTF-8'

以下两个 mb_detect_order 数组都给了我上述值

$detect_order = array('ASCII', 'UTF-8', 'Windows-1252', 'ISO-8859-1');
$detect_order = array('ASCII', 'UTF-8', 'ISO-8859-1', 'Windows-1252');

这让我很困惑!

唷,有人可以对此有所了解吗?非常感谢!

4

3 回答 3

2

这是一个已知的错误

Windows-1251并且Windows-1252只有当整个字符串由一定范围内的高字节字符组成时才会成功。这意味着您将永远无法获得正确的转换,因为 ISO-8859-1即使文本显示为Windows-1252.

LATIN1我在从 转换为 时遇到了这个问题UTF-8。我从 Microsoft Word 粘贴了许多内容,并使用MySQL 表的字符集存储在一个VARCHAR字段中。LATIN1您可能知道 Word 将撇号和引号转换为智能撇号和弯引号。它们都不会显示在屏幕上,因为这些字符没有正确转换。文本始终标识为ISO-8859-1. 为了解决这个问题,我强制转换 from Windows-1252toUTF-8和 both,撇号和引号(和其他字符)被正确转换。

于 2014-06-11T22:07:17.270 回答
1

不确定我是否会回答你所有的问题,但我们开始吧:

据我了解,windows-1252 是 iso-8859-1 的超集,这促使我思考为什么要费心使用 utf8_encode() 呢?为什么不直接使用 iconv('Windows-1252', 'UTF-8', $str) 代替 utf8_encode() 因为 iso-8859-1 中表示的任何内容以及 windows-1252 独有的字符都会被转换

你不应该为 ut8_encode 烦恼。转到 iconv() 或 mb_convert_encoding。ut8_encode 仅将 ISO-8859-1 转换为 UTF-8。如果您需要在不同编码之间进行转换,您应该使用其他功能。

关于欧元马克。不确定这是否在某个时候(正式或非正式地)添加到 ISO-8859-1 中,但下面的两个语句都返回 true

$ansi = "€";//euro mark, the code file itself is in ansi

$detected = mb_detect_encoding($ansi, "WINDOWS-1252", TRUE);// $detected == "Windows-1252"
echo $detected."<br/>-<br/>";
$detected = mb_detect_encoding($ansi, "ISO-8859-1", TRUE);// $detected == ISO-8859-1
echo $detected."<br/>-<br/>";


$detected = mb_detect_encoding($ansi, "WINDOWS-1252");// $detected == "Windows-1252"
echo $detected."<br/>-<br/>";
$detected = mb_detect_encoding($ansi, "ISO-8859-1");// $detected == ISO-8859-1
echo $detected."<br/>-<br/>";

请注意,这是将 strict 设置为 True 或 False 的结果。这或许可以解释为什么

我的 $detect_order = array('ASCII', 'ISO-8859-1', 'Windows-1252','UTF-8'); 我知道这是不正确的,因为它给了我以下结果

为您提供 ISO-8859-1。我注意到你在 ISO 之后切换了 UTF-8,这就是为什么它最后给了你 UTF-8。

为什么我的 ('ASCII', 'ISO-8859-1', 'Windows-1252','UTF-8') 的检测顺序对于我想要得到的东西是错误的?

根据 php 的网站http://us3.php.net/manual/en/function.mb-detect-order.php,在 UTF-8 之前设置 ISO 将始终返回 ISO。检查他们的无用检测命令示例。

从我看到的情况来看,如果您同时拥有 ISO-8859-1 和 Windows-1252,那么您将获得 ISO。如果您取出其中一个或另一个,您将得到两者剩下的任何东西。所以下面最后2个的定位似乎没有什么区别

$detect_order = array('ASCII', 'UTF-8', 'Windows-1252', 'ISO-8859-1'); $detect_order = array('ASCII', 'UTF-8', 'ISO-8859-1', 'Windows-1252');

于 2011-11-17T16:04:50.330 回答
-3

€ 符号不是 utf8 编码的一部分!

你必须把它写成€!

或编码为 windows-1252 或 iso-8859-15(与 iso-8859-1 相同,但有 € 符号)

于 2012-12-22T16:07:49.373 回答