Включение новых строк в функцию замены PHP preg


Я пытаюсь сопоставить строку, которая может отображаться в нескольких строках. Он начинается и заканчивается определенной строкой:

{a}some string
can be multiple lines
{/a}

Могу ли я захватить все между {a} и {/a} с помощью регулярного выражения? Похоже на то. не соответствует новым строкам, но я безуспешно пробовал следующее:

$template = preg_replace( $'/\{a\}([.\n]+)\{\/a\}/', 'X', $template, -1, $count );
echo $count; // prints 0

Это совпадает. или \n, когда они сами по себе, но не вместе!

Author: DisgruntledGoat, 2009-03-30

3 answers

Используйте s модификатор:

$template = preg_replace( $'/\{a\}([.\n]+)\{\/a\}/s', 'X', $template, -1, $count );
//                                                ^
echo $count;
 32
Author: strager, 2009-03-30 01:39:09

Я думаю, что у вас больше проблем, чем просто точка, не совпадающая с новыми строками, но позвольте мне начать с рекомендации по форматированию. В качестве разделителя регулярных выражений можно использовать практически любой знак препинания, а не только косую черту ('/'). Если вы используете другой символ, вам не придется избегать косых черт в регулярном выражении. Я понимаю, что "%" популярно среди PHPers; это сделало бы ваш аргумент шаблоном:

'%\{a\}([.\n]+)\{/a\}%'

Теперь причина, по которой регулярное выражение не сработало так, как вы предполагали, заключается в том, что точка теряет свое особое значение, когда оно появляется внутри класса символов (квадратные скобки) - поэтому [.\n] просто соответствует точке или переводу строки. То, что вы искали, было (?:.|\n), но я бы рекомендовал сопоставить возврат каретки, а также перевод строки:

'%\{a\}((?:.|[\r\n])+)\{/a\}%'

Это потому, что слово "новая строка" может относиться к "\n" в стиле Unix, "\r\n" в стиле Windows или "\r" в стиле более старых компьютеров Mac. Любая данная веб-страница может содержать любой из них или смесь двух или более стилей; сочетание "\n" и "\r\n" является очень распространенный. Но в режиме /s (также известном как однострочный или точечный режим) вам не нужно беспокоиться об этом:

'%\{a\}(.+)\{/a\}%s'

Однако есть еще одна проблема с исходным регулярным выражением, которая все еще присутствует в этом: + является жадным. Это означает, что если в тексте более одной последовательности {a}...{/a}, при первом применении вашего регулярного выражения оно будет соответствовать всем из них, от первого {a} до последнего {/a}. Самый простой способ исправить это - сделать + нескладным (он же "ленивый" или "неохотно"), добавив знак вопроса:

'%\{a\}(.+?)\{/a\}%s'

Наконец, я не знаю, что делать с "$" перед вступительной цитатой вашего аргумента шаблона. Я не занимаюсь PHP, но для меня это выглядит как синтаксическая ошибка. Если бы кто-нибудь мог просветить меня в этом вопросе, я был бы признателен.

 7
Author: Alan Moore, 2009-03-30 06:42:31

Из http://www.regular-expressions.info/dot.html:

"Точка соответствует одному символу, не заботясь о том, что это за символ. Единственным исключением являются символы новой строки"

.

Вам нужно будет добавить флаг завершения /s к вашему выражению.

 3
Author: John T, 2009-03-29 23:48:41