Включение новых строк в функцию PHP preg_replace

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

{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 когда они сами по себе, но не вместе!


person DisgruntledGoat    schedule 29.03.2009    source источник


Ответы (3)


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

$template = preg_replace( $'/\{a\}([.\n]+)\{\/a\}/s', 'X', $template, -1, $count );
//                                                ^
echo $count;
person strager    schedule 29.03.2009
comment
Удивительно, я знал, что это будет что-то простое! - person DisgruntledGoat; 30.03.2009
comment
Кроме того, я только что обнаружил, что эта информация ЕСТЬ на веб-сайте PHP, хотя я никогда не находил ее раньше при поиске... php.net/manual/en/reference.pcre.pattern.modifiers.php - person DisgruntledGoat; 30.03.2009

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

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

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

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

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

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

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

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

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

person Alan Moore    schedule 30.03.2009
comment
О, это должно быть опечатка - я изначально использовал там переменную и заменил ее строкой для этого примера. - person DisgruntledGoat; 03.04.2009
comment
Это было отличное объяснение. Спасибо за это. - person craignewkirk; 31.03.2016

С http://www.regular-expressions.info/dot.html:

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

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

person John T    schedule 29.03.2009