我有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
吗? (返回一个匹配数组及其在字符串中的位置)
答案 0 :(得分:6)
这不是错误,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);
给出:
Array ( [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;
}
答案 1 :(得分:3)
有一个简单的解决方法,在preg_match()结果匹配后使用。您需要迭代每个匹配结果并使用以下内容重新分配位置值:
$utfPosition = mb_strlen(substr($wholeSubjectString, 0, $capturedEntryPosition), 'utf-8');
在Windows下的php 5.4上测试,仅依赖于Multibyte PHP扩展。
答案 2 :(得分:0)
PHP不支持unicode,因此许多字符串函数(包括preg_ *)仍然计算字节而不是字符。
我尝试通过编码和解码字符串来寻找解决方案,但最终归结为preg_match_all函数。
关于python的事情:python regex matchobject默认包含匹配位置mo.start()和mo.end()。请参阅:http://docs.python.org/library/re.html#finding-all-adverbs-and-their-positions
答案 3 :(得分:0)
如何通过正则表达式分割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