2010-11-20 1 views
2

Это не работает, то получается, что это бред:Почему preg_split PHP разделяет букву «נ» на иврите в UTF-8 при разделении на « s»?

$foo = 'נ'; 
$bar = mb_convert_encoding($foo, 'UTF-8', mb_detect_encoding($foo)); 
print_r(preg_split('/\s/', $bar)); 

Array ([0] => [1] =>)

Но это работает:

$foo = 'נ'; 
$bar = mb_convert_encoding($foo, 'ISO-8859-8', mb_detect_encoding($foo)); 
$baz = preg_split('/\s/', $bar); 
echo(mb_convert_encoding($baz[0], 'UTF-8', 'ISO-8859-8')); 

נ

Проблема заключается только в письме «נ». Он отлично работает со всеми другими ивритскими буквами. Есть ли решение для этого?

ответ

7

При работе с данными в кодировке UTF-8, всегда используйте u modifier в вашей модели:

/\s/u 

Потому что в противном случае шаблон не интерпретируется как UTF-8.

Как и в этом случае символ נ (U + 05E0) кодируется 0xD7A0 в UTF-8. И \s представляет любой символ пробела (в соответствии с PCRE):

The \s персонажей HT (9), LF (10), FF (12), CR (13), и пространство (32).

При добавлении UTF-8 поддержка, они также добавили специальную опцию под названием PCRE_UCP иметь \b, \d, \s и \w не просто соответствуют US-ASCII символы, но и другие символы Юникода по их свойствам Unicode:

по умолчанию в режиме UTF-8, символы со значениями больше 128 никогда не совпадают \d, \s или \w, и всегда соответствуют \D, \S и \W. [...] Тем не менее, если PCRE скомпилирован с поддержкой свойств Unicode, а опция PCRE_UCP устанавливается, поведение изменяется таким образом, что свойства Unicode используются для определения типов символов, следующим образом:

  • \d любой символ, который \p{Nd} спички (десятичное число)
  • \s любой символ, \p{Z} матчей, плюс ХТ, LF, FF, CR
  • \w любой символ, \p{L} или \p{N} матчей, а также подчеркнуть

И это неразрывное пространство U + 00A0 обладает свойством сепаратора (\p{Z}).

Таким образом, хотя ваш шаблон не в UTF-8 режиме, кажется, что \sделает матч, который 0xA0 в кодовом слове UTF-8 0xD7A0, разделив строку в этой позиции и возвращает массив, который эквивалентен array("\xD7", "") ,

И это, очевидно, ошибка, как картина не в режиме UTF-8, но 0xA0 является больше 0x80 (дополнительно 0xA0 бы быть закодированы как 0xC2A0). С этим можно связать bug #52971 PCRE-Meta-Characters not working with utf-8.

+0

это работает! Спасибо! – happytoad

+0

@happytoad: Я добавил некоторые возможные объяснения для этого конкретного поведения. – Gumbo

+0

Люди, которые интересуются отношениями между символами Юникода и свойствами Юникода, включая такие вещи, как '\ s' и' \ v' (вертикальное пространство) и '\ h' (горизонтальное пространство), должны захватить две мои основные программы утилиты, [ * unichars *] (http://training.perl.com/scripts/unichars) и [* uniprops *] (http://training.perl.com/scripts/uniprops). Включаются инструкции и примеры. Существует также третья связанная программа, [* uninames *] (http://training.perl.com/scripts/uninames), которая вам также может понравиться. – tchrist