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

Я уже знаю, что \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?

Ответы [ 3 ]

13 голосов
/ 19 декабря 2009

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

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

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

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

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

10 голосов
/ 01 апреля 2014

Комментарий в коде Друпала - НЕПРАВИЛЬНО .

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

7 голосов
/ 06 апреля 2014

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

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

Это относится к сортировке по индексу символов во внутренних таблицах символов PCRE, которые можно настроить в соответствии с текущей локалью, используя pcre_maketables. Эта функция строит таблицы в порядке значения символа (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 (используя свою собственную, очень особенную, изготовленную на заказ определение локали), вы могли бы , в случае EBCDIC, включать другие непреднамеренные символы. А для других диапазонов «сопоставление в последовательности ASCII» не совсем точно.

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

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

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

...