【问题标题】:UTF-8 characters in preg_match_all (PHP) [duplicate]preg_match_all (PHP) 中的 UTF-8 字符
【发布时间】:2011-01-12 08:34:04
【问题描述】:

我有preg_match_all('/[aäeëioöuáéíóú]/u', $in, $out, PREG_OFFSET_CAPTURE);

如果$in = 'hëllo' $out 是:

array(1) {
[0]=>
  array(2) {
  [0]=>
    array(2) {
      [0]=>
      string(2) "ë"
  [1]=>
  int(1)
}
[1]=>
array(2) {
  [0]=>
  string(1) "o"
  [1]=>
  int(5)
  }
}
}

o 的位置应该是 4。我已经在网上阅读过这个问题(ë 被计为 2)。有解决方案吗?我见过mb_substr 和类似的东西,但是preg_match_all 有类似的东西吗?

有点相关:它们是否相当于 Python 中的preg_match_all? (返回匹配数组及其在字符串中的位置)

【问题讨论】:

  • 你应该在另一个问题中问这个问题,但是是的...... python 正则表达式匹配对象默认包含匹配位置 mo.start() 和 mo.end()

标签: php regex pcre


【解决方案1】:

PHP 对 unicode 的支持不是很好,所以很多字符串函数,包括 preg_*,仍然计算字节而不是字符。

我尝试通过编码和解码字符串来寻找解决方案,但最终都归结为 preg_match_all 函数。

关于 python 的事情:python 正则表达式匹配对象默认包含匹配位置 mo.start() 和 mo.end()。见:http://docs.python.org/library/re.html#finding-all-adverbs-and-their-positions

【讨论】:

  • 显然它计划在 PHP6 中修复,但到目前为止,2016 年(6 年后)它仍然只是在讨论中。一定要爱 PHP 开发人员。他们没有实际的线索。
【解决方案2】:

另一种通过正则表达式拆分 UTF-8 $string 的方法是使用函数 preg_split()。这是我的工作解决方案:

    $result = preg_split('~\[img/\d{1,}/img\]\s?~', $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);

PHP 5.3.17

【讨论】:

    【解决方案3】:

    有一个简单的解决方法,可以在 preg_match() 结果匹配后使用。您需要迭代每个匹配结果并使用以下内容重新分配位置值:

    $utfPosition = mb_strlen(substr($wholeSubjectString, 0, $capturedEntryPosition), 'utf-8');
    

    在 Windows 下的 php 5.4 上测试,仅依赖于多字节 PHP 扩展。

    【讨论】:

      【解决方案4】:

      这不是bug,PREG_OFFSET_CAPTURE指的是字符串中字符的字节偏移量。

      mb_ereg_search_pos 的行为方式相同。一种可能是之前将编码改为UTF-32,然后将位置除以4(因为在UTF-32中所有的unicode代码单元都表示为4字节序列):

      mb_regex_encoding("UTF-32");
      $string = mb_convert_encoding('hëllo', "UTF-32", "UTF-8");
      $regex =  mb_convert_encoding('[aäeëioöuáéíóú]', "UTF-32", "UTF-8");
      mb_ereg_search_init ($string, $regex);
      $positions = array();
      while ($r = mb_ereg_search_pos()) {
          $positions[] = reset($r)/4;
      }
      print_r($positions);
      

      给予:

      大批 ( [0] => 1 [1] => 4 )

      您还可以将二进制位置转换为代码单元位置。对于 UTF-8,次优实现是:

      function utf8_byte_offset_to_unit($string, $boff) {
          $result = 0;
          for ($i = 0; $i < $boff; ) {
              $result++;
              $byte = $string[$i];
              $base2 = str_pad(
                  base_convert((string) ord($byte), 10, 2), 8, "0", STR_PAD_LEFT);
              $p = strpos($base2, "0");
              if ($p == 0) { $i++; }
              elseif ($p <= 4) { $i += $p; }
              else  { return FALSE; }
          }
          return $result;
      }
      

      【讨论】:

        猜你喜欢
        • 2016-05-31
        • 2012-06-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-15
        • 1970-01-01
        • 1970-01-01
        • 2010-11-28
        • 1970-01-01
        相关资源
        最近更新 更多