UTF-8的正则表达式测试

时间:2013-11-17 23:41:56

标签: php encoding utf

今天我决定测试一个小函数,检查字符串是否为UTF-8。

我使用Multilingual form encoding的推荐并创建了一个小帮手:

function is_utf8($string) {
    if (strlen($string) == 0)
    {
        return true;
    }

    return preg_match('%^(?:
        [\x09\x0A\x0D\x20-\x7E]              # ASCII
        | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
        |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
        | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
        |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
        |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
        | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
        |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
    )*$%xs', $string);
}

作为测试,我使用了一个包含196个字符的字符串。然后检查了我的助手。但是浏览器不会显示带有结果的页面 - 而是找不到404页面。

$string = "1234567890123456789012345678..."; // 196 characters here
echo strlen($string); // result - 196
var_dump(is_utf8($string)); // Error - Page not found!

但如果我使用195个字符,一切正常。

我尝试过任何角色,甚至是空格。此函数仅适用于不超过195个字符的字符串。

为什么?

3 个答案:

答案 0 :(得分:1)

这也适用于简单的正则表达式和序列化

function check_utf8($str) {
     return (bool)preg_match('//u', serialize($str));
}

答案 1 :(得分:1)

做了一个简单的测试。 我执行了1000000次的功能。看谁更快。 我还要感谢@mario提供原子分组的帮助。

$string = "ывлдоkfdsuLIU(*knj4k58u7MJHKkiyhsf9hfhlknhlkjldfivjo8iulkjlgs".
          "2345678901234567890123456789012345678901234567890123456789012".
          "ыдваолт ДЛЯОЧДльы0щ39478509г0*()*?Щчялртодылматцю4к 2ылвсголо".
          "4567890123456789012345678901234567890123456789012345678901234".
          "4567890123456789012345678901234567890123456789012345678901234".
          "asdfsd ds.kjasldasjlKUJLjLKZjulizL kzjxLkUJOLIULKM.LKl;.mcvss";

$s = microtime(true);

for ($i=0; $i<1000000; $i++)
{
        // algorithm
}

$e = microtime(true);

echo $e-$s; 

结果如下:

preg_match('//u', $string )

结果: 11.634791135788

(preg_match('%^(?>
                [\x09\x0A\x0D\x20-\x7E]              # ASCII
                | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
                |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
                | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
                |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
                |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
                | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
                |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
            )*$%xs', $string)

结果:致命错误:超过最长执行时间30秒

preg_match('/^./su', $string)

结果: 12.27244400978

mb_detect_encoding($string, array('UTF-8'), true)

结果: 15.370143890381

我也尝试过@helloworld

提出的方法
preg_match('//u', serialize($string))

结果: 23.193331956863 sec

谢谢大家的意见! 你帮我理解了

答案 2 :(得分:1)

如果字符串太长 - &gt; PCRE崩溃

查看http://www.java-samples.com/showtutorial.php?tutorialid=1526以解决问题