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

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

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

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

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

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

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

Тем не менее, путь PHP слепо обрабатывает строки, поскольку коллекции байтов, а не набор кодовых точек UTF, означает, что у вас есть ситуация, когда az MIGHT соответствует акцентированному символу . Учитывая разнообразие различных систем, к которым развертывается Drupal, имеет смысл, что они будут выбирать явную информацию о допустимых символах, а не просто доверять az, чтобы делать правильные вещи.

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

Обновление в 2014 году . Ниже представлен ответ от JimmiTh: (несмотря на некоторую документацию «confusing-to-non-pcre-core-developers»), что [az] будет соответствовать символам abcdefghijklmnopqrstuvwxyz в 99% случаев в предисловии. Тем не менее, разработчики рамок, как правило, испытывают раздражение относительно неопределенности в своем коде, особенно когда код использует системы (специфические для локалирования строки), которые PHP не обрабатывает так грациозно, как хотелось бы, и серверы, над которыми разработчики не имеют контроля. Хотя анонимные комментарии разработчика Drupal неверны – дело не в том, чтобы «получить [az] путать с \w », но вместо этого разработчик Drupal был неясным / неуверенным в том, как PCRE обрабатывает [az] и выбирает более конкретную форму abcdefghijklmnopqrstuvwxyz чтобы обеспечить конкретное поведение, которое они хотели.

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

Это НЕправда, что « international characters (eg German umlauts) » могут совпадать с [az] .

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

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

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

 yes no no no 

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

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

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

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

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

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

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). Вы можете сделать это, если используете нестандартный язык. Функция дает указатель на таблицы.

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

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

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

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

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