Будет ли [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
?
Ответы
Ответ 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], то есть относятся к порядку кода, а не к порядку сортировки.