Подтвердить что ты не робот

Будет ли [a-z] когда-либо соответствовать ударным символам в PREG/PCRE?

Я уже знаю, что \w в PCRE (в частности, реализация PHP) иногда может сопоставляться с некоторыми символами, отличными от ASCII, в зависимости от языка системы, но как насчет [a-z]?

Я бы так не думал, но я заметил эти строки в одном из файлов ядра Drupal (включая/theme.inc, упрощенное):

// To avoid illegal characters in the class,
// we're removing everything disallowed. We are not using 'a-z' as that might leave
// in certain international characters (e.g. German umlauts).
$body_classes[] = preg_replace('![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s', '', $class);

Это правда, или кто-то просто путал [a-z] с \w?

4b9b3361

Ответ 1

Короче говоря: может быть, зависит от системы, в которую развертывается приложение, зависит от того, как скомпилирован PHP, добро пожаловать в CF локализации и интернационализации.

Основной механизм PCRE учитывает локаль при определении того, что означает "a-z". В испанском языковом языке, - был бы пойман a-z). Семантическим значением a-z является "все буквы между a и z и - это отдельное письмо на испанском языке.

Однако способ, которым PHP слепо обрабатывает строки как коллекции байтов, а не набор кодовых точек UTF, означает, что у вас есть ситуация, когда a-z MIGHT соответствует символу с акцентом. Учитывая разнообразие различных систем, к которым развертывается Drupal, имеет смысл, что они предпочтут быть явным о разрешенных символах, а не просто доверять a-z, чтобы поступать правильно.

Я также предполагаю, что существование этого регулярного выражения является результатом сообщения об ошибке, о том, что немецкие умляуты не фильтруются.

Обновление в 2014 году: в JimmiTh ответ ниже, он выглядит (несмотря на некоторые "запутывающие-не-pcre-core- разработчики" ), что [a-z] будет соответствовать символам abcdefghijklmnopqrstuvwxyz пословицей 99% времени. Тем не менее, разработчики рамок, как правило, испытывают раздражение относительно неопределенности в своем коде, особенно когда код использует системы (специфические для локалирования строки), которые PHP не обрабатывает так грациозно, как хотелось бы, и серверы, над которыми разработчики не имеют контроля. Хотя анонимные комментарии разработчика Drupal неверны - дело не в том, чтобы "получить [a-z] в путанице с \w", но вместо этого разработчик Drupal не понял/не понял, как обрабатывается PCRE [a-z], и выбирая более конкретные формы abcdefghijklmnopqrstuvwxyz, чтобы обеспечить конкретное поведение, которое они хотели.

Ответ 2

комментарий в коде Drupal WRONG.

Это НЕ true, что "international characters (e.g. German umlauts)" может соответствовать [a-z].

Если, например, у вас есть немецкий язык, вы можете проверить его следующим образом:

setlocale(LC_ALL, 'de_DE'); // German locale (not needed, but you never know...)
echo preg_match('/^[a-z]+$/', 'abc') ? "yes\n" : "no\n";
echo preg_match('/^[a-z]+$/', "\xE4bc") ? "yes\n" : "no\n"; // äbc in ISO-8859-1
echo preg_match('/^[a-z]+$/',  "\xC3\xA4bc") ? "yes\n" : "no\n"; // äbc in UTF-8
echo preg_match('/^[a-z]+$/u', "\xC3\xA4bc") ? "yes\n" : "no\n"; // w/ PCRE_UTF8

Выход (не изменится, если вы замените de_DE на de_DE.UTF-8):

yes
no
no
no

Класс символов [abcdefghijklmnopqrstuvwxyz] идентичен [a-z] в обоих кодировках, которые понимает PCRE: ASCII-производный монобайт и UTF-8 (который также является ASCII-производным). В обоих этих кодировках [a-z] совпадает с [\x61-\x7A].

В 2009 году вопрос мог быть другим, но в 2014 году нет "странной конфигурации", которая может заставить PHP-ретранслятор PHP PCRE интерпретировать [a-z] как класс более 26 символов (до тех пор, пока [a-z] сам записывается как 5 байтов в кодировке, основанной на ASCII, конечно).

Ответ 3

Просто добавление как к уже отличным, так и противоречивым ответам.

Документация для библиотеки PCRE всегда указывала, что "Диапазоны работают в последовательности сортировки значений символов". Это несколько расплывчато, но очень точно.

Он ссылается на сопоставление индексов символов в внутренних таблицах символов PCRE, которые могут быть настроены так, чтобы соответствовать текущему языку, используя pcre_maketables. Эта функция строит таблицы в порядке char значения (tolower(i)/toupper(i))

Другими словами, он не сопоставляется фактическим порядком культурной сортировки (информация о сортировке локали). В качестве примера, в то время как немецкий рассматривает ö так же, как o в сортировке словаря, ö имеет значение, которое заставляет его отображаться вне диапазона az во всех обычных кодировках символов, используемых для немецкого языка (ISO-8859-x, кодировки Unicode и т.д.). в этом случае PCRE основывал бы свое определение того, находится ли ö в диапазоне [a-z] от этого значения кода, а не с каким-либо фактическим порядком сортировки по локали.

PHP в основном скопировал документацию PCRE в свои документы. Тем не менее, они действительно пошли на изменения, изменив приведенное выше утверждение на "Диапазоны работают в последовательности сортировки ASCII". Это выражение было в документах, по крайней мере, с 2004 года.

Несмотря на вышеизложенное, я не совсем уверен, что это правда.

Ну, не во всех случаях, по крайней мере.

Один вызов PHP делает для pcre_maketables... Из источника PHP:

#if HAVE_SETLOCALE
    if (strcmp(locale, "C"))
        tables = pcre_maketables();
#endif

Другими словами, если среда, для которой скомпилирована PHP, имеет setlocale, а локаль (LC_CTYPE) не является языковой версией POSIX/C, используется последовательность символов языка POSIX/C в среде выполнения. В противном случае используются таблицы PCRE по умолчанию - которые генерируются (посредством pcre_maketables) при компиляции PCRE - на основе локали компилятора:

Эта функция создает набор таблиц символов для значений символов меньше 256. Они могут быть переданы pcre_compile() для переопределения внутренних встроенных таблиц PCRE (которые были сделаны pcre_maketables() при компиляции PCRE). Вы можете сделать это, если используете нестандартный язык. Функция дает указатель на таблицы.

В то время как немецкий не будет отличаться для [a-z] в любой общей кодировке символов, если бы мы имели дело с EBCDIC, например, [a-z] включал бы ± и ~. Конечно, EBCDIC - это кодировка одного символа, о которой я могу думать, не помещая a-z и A-Z в непрерывную последовательность.

Если PCRE не делает какой-либо магии при использовании EBCDIC (и может быть), в то время как маловероятно, что вы включили умлауты во что угодно, кроме самой неясной среды сборки PHP или среды выполнения (используя ваш собственный, очень специальный, выполненный на заказ locale), вы можете, в случае EBCDIC, включить другие непреднамеренные символы. А для других диапазонов "сопоставление в последовательности ASCII" выглядит не совсем точно.

ETA: Я мог бы сэкономить некоторое исследование, если бы искал собственный ответ Филиппа Хейзела:

  

Другая проблема связана с диапазонами классов символов. Вы могли бы подумать, что [a-k] и [x-z] хорошо определены для латинских скриптов, но это не так.

  

Они, безусловно, четко определены, эквивалентны [\ x61-\x6b] и [\ x78-\x7a], то есть относятся к порядку кода, а не к порядку сортировки.