【发布时间】:2021-10-11 20:52:40
【问题描述】:
有几种方法可以在 PHP 中检查字符串是否为有效的 UTF-8,但有没有人实际进行基准测试以检查哪种方法更快?
检查我是否知道的方法(也许它遗漏了什么,idk):
function is_utf8_1(string $str): bool
{
return mb_check_encoding($str, 'UTF-8');
}
function is_utf8_2(string $str): bool
{
return (bool) preg_match('//u', $str);
}
function is_utf8_3(string $str): bool
{
return iconv('UTF-8', 'UTF-8//IGNORE', $str) === $str;
}
// DO NOT USE is_utf8_4, it is bugged, it incorrectly validates "\xC0\x81"
//
// in 2009 the author made the claim that
// this method is more accurate than mb_check_encoding,
// without providing any examples of where mb_check_encdoing fails and this function succeeds...
// source: https://www.php.net/manual/en/function.mb-check-encoding.php#95289
function is_utf8_4(string $str): bool
{
$len = strlen($str);
for ($i = 0; $i < $len; ++ $i) {
$c = ord($str[$i]);
if ($c > 128) {
if (($c > 247))
return false;
elseif ($c > 239)
$bytes = 4;
elseif ($c > 223)
$bytes = 3;
elseif ($c > 191)
$bytes = 2;
else
return false;
if (($i + $bytes) > $len)
return false;
while ($bytes > 1) {
++ $i;
$b = ord($str[$i]);
if ($b < 128 || $b > 191)
return false;
-- $bytes;
}
}
}
return true;
}
【问题讨论】:
-
如果您需要检查数万亿个字符串,这种差异实际上很重要,您需要在特定平台上对自己的数据进行自己的基准测试。在任何其他情况下,只需使用专门用于此目的的函数:
mb_check_encoding。 -
听起来您的问题的一个重要部分是声称
is_utf8_4的“比mb_check_encoding更准确”,以及这是否值得它可能涉及的任何性能成本。您可能应该链接您找到它的位置。 -
@deceze 似乎 preg_match 比 mb_check_encoding 快 SIGNIFICANTLY,比如快 30 倍(!!!),这让我想知道我是否在基准测试代码中犯了错误不知何故.. 或者 mb_check_encoding 以某种方式存在性能问题(或者也许有人在优化 preg_match 上花费了比任何人优化 mb_check_encoding 更多的精力?比如 preg_match 使用 SSE 指令,而 mb_ 不是?idk)
-
@PeterCordes 我在源代码中添加了链接,我并不怀疑 mb_check_encoding 的准确性,该代码/评论是 11 年前(2009-12-24)写的,如果有的话11 年前
mb_check_encoding($str,'UTF-8')的已知问题,很有可能从那时起已经修复 :) -
@deceze 似乎 failure_early 完全没有使用 mb_check_encoding 进行优化,它使用基本上相同的时间检查字符串,无论第一个无效字节是在位置 0 还是位置 4690,就像在我的基准代码中一样下面,建议
early return优化可以使 mb_check_encoding 在坏/二进制数据情况下比现在快得多,嗯
标签: php performance utf-8 benchmarking