为什么这个正则表达式尽可能匹配尽可能少的字符,即使没有问号?

时间:2015-08-12 20:01:58

标签: regex

我正在使用这个表达式:

(.*(?:<br\/>(?:<\/p>)?\n.*)+)

在此示例文本中:

test text <br/>
test line2 <br/>
test line3 <br/>
test line4

不是将此作为一个完整的匹配,而是分为两个匹配(当使用g标志时,否则它只是第一个匹配):

MATCH ONE: 
test text <br/>
test line2 <br/>

MATCH TWO:
test line3 <br/>
test line4

(链接到示例:https://www.regex101.com/r/lS9vV7/3

编辑:此表达式应匹配整个字符串,而不是将其拆分为两个匹配

2 个答案:

答案 0 :(得分:2)

而不是content (br \n content)*,将其更改为(content br \n)* content

(?:.*<br\/>(?:<\/p>)?\n)+.*

Demo on regex101

原始正则表达式和上面的解决方案具有相同的匹配能力,即如果您锚定正则表达式,则两个解决方案匹配相同的语言(满足以下条件的字符串集)正则表达式定义的语法)。但是,由于回溯机制和在回溯引擎中探索搜索树的顺序,结果不同。

在贪婪量词(例如*+{n,}{n,m})满足重复的下限后,它会尝试将原子与原子匹配多次可能,并且未能匹配下一个原子,它会停止重复并继续续集模式。虽然它可以回溯到原子,也可以撤消重复,但只有在续集模式失败时才会发生回溯。在我们的例子中,没有续集模式(换句话说,我们接受匹配)。

正如在另一个答案中所分析的那样,.*中的第二个(.*(?:<br\/>(?:<\/p>)?\n.*)+)可以匹配<br/>,这意味着下一次重复没有</br>。由于如上所述的回溯机制,量词+停止尝试更多,并且接受匹配(因为没有续集模式)。

(作为续集的一个例子,当你在结尾添加锚\z时,\z是续集,阻止匹配发生在输入字符串的中间。)

在我的解决方案中,为了阻止重复的外部重复,模式.*<br\/>(?:<\/p>)?\n必须失败,这意味着它必须通过回溯来尝试所有可能性。这允许.*回溯以匹配行尾的<br/>

答案 1 :(得分:1)

尝试:

(.*(?:<br\/>(?:<\/p>)?\n[^<]*)+)

DEMO

我认为你的正则表达式不起作用,因为在.+之后的\n也匹配了下一个<br/>部分(look here),所以{{ 1}}多次都没有工作。如果您将(?:<br\/>(?:<\/p>)?\n[^<]*)+替换为[^<]+,则它将与.+不匹配,并且它应该按预期工作(至少我希望如此)。