正则表达式在多行上太贪婪了


regex too greedy over multiple lines

我有以下代码:

$text = "Lorem ipsum dolor sit amet, [b]consectetur adipiscing elit[/b]. 
Nunc lorem velit, lacinia ut commodo in, suscipit vitae magna. 
Nam imperdiet neque blandit semper tempus. 
Curabitur sapien ante, vestibulum vitae ante a, condimentum dignissim tortor. Aenean adipiscing tincidunt lorem, non eleifend tellus suscipit a. Nulla convallis [b]
pulvinar ligula[/b], at tempor ante. Fusce a tellus enim. Vivamus nibh eros, ultrices at auctor quis, fringilla nec dolor. Aenean nec tincidunt odio, id pulvinar felis. Pellentesque in augue volutpat, gravida nibh eu, lobortis augue.";
preg_match_all("#('[b'].*'[/b'])#s", $text, $value);

我的$value是从第一个 [b] 返回到最后一个 [/b]。我需要它单独匹配每对。

据我了解,我必须使用末尾的s来选择多行,但*太贪婪了。我不能只使用?因为我的字符数可能会有所不同......我错过了什么?

这是一个常见的错误。除非您采取措施避免它,否则正则表达式引擎将找到可能与您的模式匹配的最长子字符串。根据上下文的不同,可能会有各种可能的解决方案,但对于支持 Perl 正则表达式语法的引擎,最简单的通常是使用您正在使用的重复运算符的"非贪婪"变体。也就是说,*?而不是*+?而不是+??而不是?{m,n}?而不是{m,n}

因此,在您的示例中,模式应为:

preg_match_all("#('[b'].*?'[/b'])#s", $text, $value);

避免惰性量词的另一种方法:

preg_match_all('~'[b](?>[^[]++|'[(?!/b]))*+'[/b]~', $text, $value);

这样,您可以避免两个问题:

  1. 贪婪量词不是问题,因为字符类在每个左方括号处停止
  2. 由于您不使用点,因此您不关心"s"修饰符和换行符。