Будет ли [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?

Author: Garrett Albright, 2009-12-18

3 answers

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

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

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

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

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

 13
Author: Alan Storm, 2017-05-23 12:15:42

Комментарий в коде Drupal НЕВЕРЕН.

Это НЕ правда, что "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 году не существует "странной конфигурации", которая могла бы заставить механизм регулярных выражений PCRE PHP интерпретировать [a-z] как класс из более чем 26 символов (если, конечно, [a-z] сам записывается как 5 байт в кодировке, полученной из ASCII).

 10
Author: Walter Tross, 2014-04-04 20:47:54

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

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

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

Другими словами, он не сопоставляется по фактическому порядку сортировки по культуре (информация о сопоставлении локали). В качестве примера, в то время как немецкий язык трактует ö так же, как o в сопоставлении словарей, ö имеет значение, которое выводит его за пределы диапазона a-z во всех распространенных кодировках символов, используемых для немецкого языка (ISO-8859-x, кодировки юникода и т.д.). В этом случае 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 или среды выполнения (используя ваше собственное, очень специальное, сделанное на заказ определение локали), вы можете , в случае EBCDIC, включить другие непреднамеренные символы. И для других диапазонов "сопоставленные в последовательности ASCII" не кажутся полностью точный.

Расчетное время прибытия: Я мог бы сэкономить на некоторых исследованиях, поискав собственный ответ Филипа Хейзела на аналогичную проблему:

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

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

 7
Author: JimmiTh, 2014-04-09 06:50:04