问题在于
’
解码为Unicode字符U+0092,UTF-8编码为
C2 92
,也称为“私有使用两个”:
$ php test.php | xxd
0000000: 5374 616e c292 73 Stan..s
即这不是转换为普通的撇号。
html_entity_decode($string)
有效是因为它实际上没有解码该实体,因为默认目标字符集是Latin-1,无法表示此字符。如果将UTF-8指定为目标字符集,则实体实际上被解码。
该实体的目标是Windows-1252字符集:
echo iconv('cp1252', 'UTF-8', html_entity_decode('Stan’s', ENT_QUOTES, 'cp1252'));
Stan’s
引用自维基百科:
无论页面的编码如何,数字实体引用始终指向 Unicode 码点。禁止使用引用永久未定义字符和控制字符的数字引用,但换行符、制表符和回车符除外。也就是说,十六进制范围为 00-08、0B-0C、0E-1F、7F 和 80-9F 的字符不能在 HTML 文档中使用,即使通过引用也不行,所以例如 ™
是不允许的。然而,出于对早期 HTML 作者和忽略此限制的浏览器的向后兼容,某些浏览器会将 80-9F 范围内的原始字符和数字字符引用解释为表示映射到 Windows-1252 编码的字节 80-9F 的字符。
因此,这里涉及到传统的 HTML 实体,PHP 显然没有以与“一些”浏览器相同的方式处理它们。您可以检查解码后的实体是否在上述范围内,如果是,则将其转换/重新解码为 Windows-1252,然后将其转换为 UTF-8。或要求用户传递有效的 HTML。
此函数应处理传统和常规的 HTML 实体:
function legacy_html_entity_decode($str, $quotes = ENT_QUOTES, $charset = 'UTF-8') {
return preg_replace_callback('/&#(\d+);/', function ($m) use ($quotes, $charset) {
if (0x80 <= $m[1] && $m[1] <= 0x9F) {
return iconv('cp1252', $charset, html_entity_decode($m[0], $quotes, 'cp1252'));
}
return html_entity_decode($m[0], $quotes, $charset);
}, $str);
}
’
转换为其他内容,然后再应用html_entity_decode
吗? - Abs'
而不是’
将会给你想要的结果。 - adlawson’
。 - Karolis