15

我正在尝试匹配可能出现在多行上的字符串。它以特定字符串开头和结尾:

{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 当他们独自一人但不在一起时!

4

3 回答 3

33

使用s修饰符

$template = preg_replace( $'/\{a\}([.\n]+)\{\/a\}/s', 'X', $template, -1, $count );
//                                                ^
echo $count;
于 2009-03-29T23:44:27.873 回答
7

我认为您遇到的问题不仅仅是点不匹配换行符,但让我从格式建议开始。您可以使用几乎任何标点符号作为正则表达式分隔符,而不仅仅是斜杠 ('/')。如果您使用另一个字符,则不必在正则表达式中转义斜杠。我知道 '%' 在 PHPers 中很流行;这将使您的模式论点:

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

现在,正则表达式没有按您的预期工作的原因是,当点出现在字符类(方括号)中时,它失去了它的特殊含义——所以[.\n]只匹配一个点或换行符。您正在寻找的是(?:.|\n),但我会建议匹配回车符和换行符:

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

这是因为“换行符”这个词可以指代 Unix 样式的“\n”、Windows 样式的“\r\n”或旧 Mac 样式的“\r”。任何给定的网页可能包含其中任何一种或两种或多种样式的混合;"\n" 和 "\r\n" 的混合很常见。但是使用 /s 模式(也称为单行或 DOTALL 模式),您无需担心:

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

但是,原始正则表达式存在另一个问题,它仍然存在于这个问题中:+贪婪。这意味着,如果文本中有多个{a}...{/a}序列,则第一次应用正则表达式时,它将匹配所有序列,从 first{a}到 last {/a}+解决这个问题的最简单方法是通过附加一个问号来使不贪心(又名“懒惰”或“不情愿”):

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

最后,我不知道在你的模式参数的开头引号之前如何理解'$'。我不做 PHP,但这对我来说似乎是一个语法错误。如果有人可以在这件事上教育我,我将不胜感激。

于 2009-03-30T06:42:31.537 回答
3

来自http://www.regular-expressions.info/dot.html

“点匹配单个字符,而不关心那个字符是什么。唯一的例外是换行符。”

您需要在表达式中添加一个尾随 /s 标志。

于 2009-03-29T23:48:41.203 回答