UTF-8 символов в preg_match_all (PHP)

У меня есть 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_all в Python? (Возвращение массива совпадений с их позицией в строке)

Related of "UTF-8 символов в preg_match_all (PHP)"

PHP не поддерживает юникод очень хорошо, поэтому множество строковых функций, включая preg_ *, по-прежнему подсчитывают байты вместо символов.

Я попытался найти решение по строкам кодирования и декодирования, но в конечном итоге все это сводилось к функции preg_match_all.

О значении python: match-объект регулярного выражения python содержит позицию соответствия по умолчанию mo.start () и mo.end (). См .: http://docs.python.org/library/re.html#finding-all-adverbs-and-their-positions

Это не ошибка, PREG_OFFSET_CAPTURE относится к смещению байта символа в строке.

mb_ereg_search_pos ведет себя одинаково. Одна из возможностей заключается в том, чтобы изменить кодировку до UTF-32 до и затем разделить позицию на 4 (поскольку все юникодные кодовые единицы представлены как 4-байтовые последовательности в UTF-32):

 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; } 

Существует простое обходное решение, которое будет использоваться после сопоставления результатов preg_match (). Вам необходимо повторить каждый результат сопоставления и присвоить значение позиции следующим образом:

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

Протестировано на php 5.4 под Windows, зависит только от расширения Multibyte PHP.

Другим способом разделения строки 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