是PHP str

我想在UTF-8字符串上使用str_word_count()

这在PHP中安全吗? 在我看来,它应该是(特别是考虑到没有mb_str_word_count() )。

但在php.net上,有很多人通过展示他们自己的'多字节兼容'版本的功能来混淆水。

所以我想我想知道...

  • 鉴于str_word_count只是简单地计算所有由" " (空格)分隔的字符序列,所以对多字节字符串应该是安全的,即使它不一定知道字符序列,对吧?

  • UTF-8中是否有任何等效的“空格”字符,它们不是ASCII " " (空格)?#

  • 我猜这就是问题所在。


    我会说你猜对了。 实际上UTF-8中有空格字符,它们不是US-ASCII的一部分。 给你一个这样的空间的例子:

  • Unicode字符'NO-BREAK SPACE'(U + 00A0):UTF-8中的2个字节:0xC2 0xA0(c2a0)
  • 也许还有:

  • Unicode字符'NEXT LINE(NEL)'(U + 0085):UTF-8中的2个字节:0xC2 0x85(c285)
  • Unicode字符'LINE SEPARATOR'(U + 2028):UTF-8中的3字节:0xE2 0x80 0xA8(e280a8)
  • Unicode字符'PARAGRAPH SEPARATOR'(U + 2029):UTF-8中的3个字节:0xE2 0x80 0xA8(e280a8)
  • 无论如何,第一个 - 'NO-BREAK SPACE'(U + 00A0) - 就是一个很好的例子,因为它也是Latin-X字符集的一部分。 而且PHP手册已经提供了一个提示,即str_word_count将取决于语言环境。

    如果我们想要把它作为一个测试,我们可以设置语言环境为UTF-8,传递一个包含xA0序列的无效字符串,如果这仍然算作断字符,那么该函数显然不是UTF-8安全的,因此不是多字节安全的(如同每个问题一样没有定义):

    <?php
    /**
     * is PHP str_word_count() multibyte safe?
     * @link https://stackoverflow.com/q/8290537/367456
     */
    
    echo 'New Locale: ', setlocale(LC_ALL, 'en_US.utf8'), "nn";
    
    $test   = "awordxA0bword aword";
    $result = str_word_count($test, 2);
    
    var_dump($result);
    

    输出:

    New Locale: en_US.utf8
    
    array(3) {
      [0]=>
      string(5) "aword"
      [6]=>
      string(5) "bword"
      [12]=>
      string(5) "aword"
    }
    

    正如本演示所示,该函数完全失败了它在手册页上给出的语言环境承诺(我不奇怪也不会呻吟),大多数情况下,如果您阅读某个函数是PHP中的语言环境特定的,运行您的生活并找到一个这不是)我在这里利用它来证明它绝不会对UTF-8字符编码做任何事情。

    相反,对于UTF-8,您应该查看PCRE扩展:

  • 在PCRE / PHP中匹配Unicode字母字符
  • PCRE对PHP中的Unicode和UTF-8具有很好的理解。 如果您仔细制作正则表达式模式,它也可以相当快。


    关于“模板答案” - 我不明白需求“工作得更快”。 我们不是在讨论很长一段时间或很多次数,所以谁在乎是否需要几毫秒的时间呢?

    但是,使用软连字符的str_word_count:

    function my_word_count($str) {
      return str_word_count(str_replace("xC2xAD",'', $str));
    }
    

    一个符合断言的函数(但可能不会比str_word_count更快):

    function my_word_count($str) {
      $mystr = str_replace("xC2xAD",'', $str);        // soft hyphen encoded in UTF-8
      return preg_match_all('~[p{L}'-]+~u', $mystr); // regex expecting UTF-8
    }
    

    preg函数与已经提出的基本相同,除了a)它已经返回一个计数,所以不需要提供匹配,这应该使它更快,并且b)实际上不应该是iconv后备,IMO。


    关于评论:

    我可以看到,你的PCRE函数比我的preg_word_count()要慢(性能),因为需要一个你不需要的str_replace:'〜[^ p {L} ' - xC2 xAD] +〜'' !)。

    我认为一个不同的东西,字符串替换只会删除多字节字符,但你的正则表达式将以它们可能出现的任何顺序处理xC2xAD ,这是错误的。 考虑一个注册的标志,它是 xC2 xAE。

    然而,现在我认为由于有效的UTF-8工作方式,这并不重要,所以应该同样适用。 所以我们可以拥有这个功能

    function my_word_count($str) {
      return preg_match_all('~[p{L}'-xC2xAD]+~u', $str); // regex expecting UTF-8
    }
    

    不需要任何匹配或其他替换。

    关于str_word_count(str_replace(“ xC2 xAD”,'',$ str));如果用UTF8稳定,很好,但似乎不是。

    如果你阅读这个线程,你会知道str_replace是安全的,如果你坚持有效的UTF-8字符串。 我没有看到任何相反的证据。


    EDITED(显示新的线索):在PHP v5.1中使用str_word_count()有一个可能的解决方案!

    function my_word_count($str, $myLangChars="àáãâçêéíîóõôúÀÁÃÂÇÊÉÍÎÓÕÔÚ") { 
        return str_word_count($str, 0, $myLangChars);
    }
    

    但不是100%,因为我尝试添加到$ myLangChars xC2xAD (SHY - SOFT HYPHEN字符),它必须是任何语言的单词组件,并且不起作用 (请参阅参考资料)。

    另一个不是很快,而是基于PCRE库的完整而灵活的解决方案(从这里提取),但是可以选择模仿无效的UTF8上的str_word_count()行为:

     /**
      * Like str_word_count() but showing how preg can do the same.
      * This function is most flexible but not faster than str_word_count.
      * @param $wRgx the "word regular expression" as defined by user.
      * @param $triggError changes behaviour causing error event.
      * @param $OnBadUtfTryAgain when true mimic the str_word_count behaviour.
      * @return 0 or positive integer as word-count, negative as PCRE error.
      */
     function preg_word_count($s,$wRgx='/[-'p{L}xC2xAD]+/u', $triggError=true,
                              $OnBadUtfTryAgain=true) {
       if ( preg_match_all($wRgx,$s,$m) !== false )
          return count($m[0]);
       else {
          $lastError = preg_last_error();
          $chkUtf8 = ($lastError==PREG_BAD_UTF8_ERROR);
          if ($OnBadUtfTryAgain && $chkUtf8) 
             return preg_word_count(
                iconv('CP1252','UTF-8',$s), $wRgx, $triggError, false
             );
          elseif ($triggError) trigger_error(
             $chkUtf8? 'non-UTF8 input!': "error PCRE_code-$lastError",
             E_USER_NOTICE
             );
          return -$lastError;
       }
     }
    

    (模板答案)帮助赏金!

    (这不是答案,是对赏金的帮助,因为我不能编辑以复制问题)

    我们希望以UTF-8最新文本来计算“真实世界的词汇”。

    对于BOUNTY,我们需要:

  • 一个符合下面的assert并比str_word_count更快的str_word_count ;
  • str_word_count使用SHY字符(如何?);
  • preg_word_count工作更快(使用preg_replace?分词正则表达式?)。
  • ASSERTS

    假设存在“多字节安全”函数my_word_count() ,则以下断言必须为真:

    assert_options(ASSERT_ACTIVE, 1);
    
    $text = "1,2,3,4=0 (1 2 3 4)=0 (... ,.)=0  (2.5±0.1; 0.5±0.2)=0";
    assert( my_word_count($text)==0 ); // no word there 
    
    $text = "(one two,three;four)=4 (five-six sexC2xADven)=2";
    assert( my_word_count($text)==6 ); // hyphen merges two words 
    
    $text = "(um±dois três)=3 (àáãâçêéíîóõôúÀÁÃÂÇÊÉÍÎÓÕÔÚ)=1";
    assert( my_word_count($text)==4 ); // a UTF8 case 
    
    $text = "(ÍSÔ9000-X, ISÔ 9000-X, ÍSÔ-9000-X)=6"; //Codes are words?
    assert( my_word_count($text)==6 ); // suppose no: X is another word
    
    链接地址: http://www.djcxy.com/p/10175.html

    上一篇: is PHP str

    下一篇: How can I monitor and get http traffic in an android application?