10

我有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吗?

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

4

4 回答 4

7

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

mb_ereg_search_pos行为方式相同。一种可能性是之前将编码更改为 UTF-32,然后将位置除以 4(因为所有 unicode 代码单元在 UTF-32 中都表示为 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;
}
于 2010-08-08T00:23:51.463 回答
5

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

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

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

于 2014-02-27T09:39:19.707 回答
0

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

于 2010-02-02T21:14:19.733 回答
0

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

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

PHP 5.3.17

于 2014-11-19T00:06:56.777 回答