Не-ASCII символы в регулярном выражении режима UTF-8
Вопрос
Несмотря на руководство по PHP:
Почему персидские цифры совпадают \d
или же [[:digit:]]
в "режиме UTF-8"?
разработка
В замечании ответчика по несвязанному вопросу упоминается, что в регулярных выражениях \d
не только соответствует ASCII цифрам 0
через 9
но также, например, персидские цифры (۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷
).
Вышеупомянутый вопрос помечен тегом java, но поведение можно наблюдать и в PHP. Имея это в виду, я написал следующий "тест":
$string = 'I have ۳ apples and 5 oranges';
preg_match_all('/\d+/', $string, $capture);
Полученный массив $capture
содержит совпадение на 5
только
С использованием u
Модификатор для включения "UTF-8 mode" и запуска этого:
$string = 'I have ۳ apples and 5 oranges';
preg_match_all('/\d+/u', $string, $capture);
результаты в $capture
содержащие совпадения на обоих ۳
а также 5
,
Заметки
- этот вопрос относится к PHP 5.6.22 (самая новая на сегодняшний день)
- оба теста были выполнены при явном использовании
C
локали.
1 ответ
Потому что документация не работает. И это, к сожалению, не единственное место, где это так.
PHP использует PCRE под капотом для реализации своих preg_*
функции. Таким образом, документация PCRE является авторитетной. Документация PHP основана на PCRE, но, похоже, вы нашли еще одну ошибку.
Вот что вы можете прочитать в документации PCRE (выделено мной):
По умолчанию символы со значениями больше 128 не соответствуют ни одному из классов символов POSIX. Однако если
PCRE_UCP
опция передаетсяpcre_compile()
некоторые классы изменены так, что используются свойства символов Unicode. Это достигается путем замены некоторых классов POSIX другими последовательностями, как показано ниже:[:alnum:] becomes \p{Xan} [:alpha:] becomes \p{L} [:blank:] becomes \h [:digit:] becomes \p{Nd} [:lower:] becomes \p{Ll} [:space:] becomes \p{Xps} [:upper:] becomes \p{Lu} [:word:] becomes \p{Xwd}
Если вы покопаетесь в документации PHP, вы найдете следующее:
ты (
PCRE_UTF8
)Этот модификатор включает дополнительные функции PCRE, несовместимые с Perl. Шаблонные и предметные строки рассматриваются как UTF-8. Этот модификатор доступен из PHP 4.1.0 или выше в Unix и из PHP 4.2.3 в win32. UTF-8 валидность шаблона и предмета проверена начиная с PHP 4.3.5. Недопустимый предмет вызовет
preg_*
функция ничего не соответствует; неверный паттерн вызовет ошибку уровняE_WARNING
, Последовательности UTF-8 с пятью и шестью октетами считаются недействительными начиная с PHP 5.3.4 (соответственно PCRE 7.3 2007-08-28); ранее они считались действительными UTF-8.
Это, к сожалению, ложь. u
модификатор в PHP означает PCRE_UTF8 | PCRE_UCP
(UCP обозначает Свойства символов Юникода). PCRE_UCP
флаг это тот, который меняет смысл \d
, \w
и тому подобное, как вы можете видеть из документов выше. Ваши тесты подтверждают это.
В качестве примечания, не делайте свойства одного вкуса регулярного выражения из другого. Это не всегда работает (хе, даже этот график забыл о PCRE_UCP
опция).