NO-BREAK SPACE和许多其他UTF-8符号 需要2个字节才能表示 ; 因此,在UTF8字符串的假设上下文中,非ASCII(> 127)的隔离(非xC2前面)字节是一个不可识别的字符......好吧,它只是一个布局问题(!),但它破坏了整个字符串?
如何避免这种"非预期的行为"?(它出现在某些功能中,而不是在其他功能中).
示例(仅生成非预期行为preg_match):
header("Content-Type: text/plain; charset=utf-8"); // same if text/html
//PHP Version 5.5.4-1+debphp.org~precise+1
//using a .php file enconded as UTF8.
$s = "THE UTF-8 NO-BREAK\xA0SPACE"; // a non-ASCII byte
preg_match_all('/[-\'\p{L}]+/u',$s,$m);
var_dump($m); // empty! (corrupted)
$m=str_word_count($s,1);
var_dump($m); // ok
$s = "THE UTF-8 NO-BREAK\xC2\xA0SPACE"; // utf8-encoded nbsp
preg_match_all('/[-\'\p{L}]+/u',$s,$m);
var_dump($m); // ok!
$m=str_word_count($s,1);
var_dump($m); // ok
Run Code Online (Sandbox Code Playgroud)
这不是一个完整的答案,因为我没有说为什么某些 PHP 函数“在无效编码的字符串上完全失败”,而其他函数则不然:请参阅问题评论中的 @deceze 和 @hakre 答案。\n如果您正在寻找 PCRE 替代品str_word_count(),请参阅preg_word_count()下面的内容。
PS:关于“PHP5的内置库行为一致性”的讨论,我的结论是PHP5还不错,但是我们创建了很多用户定义的包装(fa\xc3\xa7ade)函数(参见多样性PHP 框架!)...或者等待 PHP6 :-)
\n\n谢谢@pebbl!如果我理解您的链接,则 PHP 上缺少错误消息。因此,我所图示的问题的一个可能的解决方法是添加一个错误条件...我在这里找到了该条件(它确保了有效的 utf8!)...并且感谢@deceze,记住存在一个用于检查此条件的内置函数(我之后编辑了代码)。
\n\n将问题放在一起,将解决方案转换为函数(已编辑,感谢 @hakre 评论!),
\n\n function my_word_count($s,$triggError=true) {\n if ( preg_match_all(\'/[-\\\'\\p{L}]+/u\',$s,$m) !== false )\n return count($m[0]);\n else {\n if ($triggError) trigger_error(\n // not need mb_check_encoding($s,\'UTF-8\'), see hakre\'s answer, \n // so, I wrong, there are no \'misteious error\' with preg functions\n (preg_last_error()==PREG_BAD_UTF8_ERROR)? \n \'non-UTF8 input!\': \'other error\',\n E_USER_NOTICE\n );\n return NULL;\n }\n }\nRun Code Online (Sandbox Code Playgroud)\n\n现在(在思考@hakre答案后进行编辑),关于统一行为:我们可以使用PCRE库开发一个合理的函数来模仿该str_word_count行为,接受错误的UTF8。对于此任务,我使用了@bobinceiconv提示:
/**\n * Like str_word_count() but showing how preg can do the same.\n * This function is most flexible but not faster than str_word_count.\n * @param $wRgx the "word regular expression" as defined by user.\n * @param $triggError changes behaviour causing error event.\n * @param $OnBadUtfTryAgain mimic the str_word_count behaviour.\n * @return 0 or positive integer as word-count, negative as PCRE error.\n */\n function preg_word_count($s,$wRgx=\'/[-\\\'\\p{L}]+/u\', $triggError=true,\n $OnBadUtfTryAgain=true) {\n if ( preg_match_all($wRgx,$s,$m) !== false )\n return count($m[0]);\n else {\n $lastError = preg_last_error();\n $chkUtf8 = ($lastError==PREG_BAD_UTF8_ERROR);\n if ($OnBadUtfTryAgain && $chkUtf8) \n return preg_word_count(\n iconv(\'CP1252\',\'UTF-8\',$s), $wRgx, $triggError, false\n );\n elseif ($triggError) trigger_error(\n $chkUtf8? \'non-UTF8 input!\': "error PCRE_code-$lastError",\n E_USER_NOTICE\n );\n return -$lastError;\n }\n }\nRun Code Online (Sandbox Code Playgroud)\n\n演示(尝试其他输入!):
\n\n $s = "THE UTF-8 NO-BREAK\\xA0SPACE"; // a non-ASCII byte\n print "\\n-- str_word_count=".str_word_count($s,0);\n print "\\n-- preg_word_count=".preg_word_count($s);\n\n $s = "THE UTF-8 NO-BREAK\\xC2\\xA0SPACE"; // utf8-encoded nbsp\n print "\\n-- str_word_count=".str_word_count($s,0);\n print "\\n-- preg_word_count=".preg_word_count($s);\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
899 次 |
| 最近记录: |