我理解?
标记在这里意味着"懒惰"。
我的问题主要是[0-9]{2}?
vs [0-9]{2}
它们是否相同?
如果是这样,我们为什么要编写前面的表达式? Aren的懒惰模式表现得更加昂贵吗?
如果没有,你能说出不同之处吗?
答案 0 :(得分:7)
与正则表达式匹配时,默认情况下指针是 greedy :
Left | Right
\d+ 12345
^ ^
\d+ 12345
^ ^^^^^ Matched!
懒惰与贪婪相反:
Left | Right
\d+? 12345
^ ^
\d+? 12345
^^ ^
12345
^
12345
^
12345
^ Matched!
在匹配中,量词*
+
?
默认为贪婪。这可能会导致不必要的行为,尤其是当我们希望某些字符仅在匹配完成时匹配时才匹配,否则会省略。
一个典型的例子是我们想要匹配单个XML标记:我们将使用<.*>
将其失败。
Left | Right
<.*> <p>hi</p><br /><p>bye</p>
^ ^
<.*> <p>hi</p><br /><p>bye</p>
^^ ^^^^^^^^^^^^^^^^^^^^^^^^
<.*> <p>hi</p><br /><p>bye</p>
^ < [backtrack!]
<.*> <p>hi</p><br /><p>bye</p>
^ ^ Matched "<p>hi</p><br /><p>bye</p>"!
Left* | Right
<.*?> <p>hi</p><br /><p>bye</p>
^ ^
<.*?> <p>hi</p><br /><p>bye</p>
^^^ ^ [can we stop? we're lazy [yes]]
<.*?> <p>hi</p><br /><p>bye</p>
^ ^ Matched "<p>"!
您可以在量词和范围后添加?
构造:
+
(一个或多个),*
(零或更多),?
(可选);
{n,m}
(n和m之间,n {n}
(正好n次)。
(示例中的n和m是实数,满足n,m∈ N )
不情愿的量词不愿继续推进。
在考虑到引擎仅尝试匹配匹配绝对必要以使剩下的其余部分成功时,允许匹配尽可能少或尽可能少。请参阅以下案例:
Left | Right
abc* abccccd
^ ^
abc* abccccd
^ ^
abc* abccccd
^ ^
abc* abccccd
^^ ^^^^ Matched "abcccc"!
Left* | Right
abc*? abccccd
^ ^
abc*? abccccd
^ ^
abc*? abccccd
^^^ ^ [must we do this? we're lazy [no]]
Matched "ab"!
如图所示,它们尽可能匹配。
不情愿的量词放弃了娱乐其他量词。
(演示目的;如果有人问,我做了不告诉你可以像这样使用RegExp。)
Left | Right
c+c+ abccccd
^ ^
c+c+ abccccd
^^ ^^^^
c+c+ abccccd
^ < [backtrack]
c+c+ abccccd
^^ ^ Matched "cccc"!
(c+ -> @ccc; c+ -> @c)
Left* | Right
c+?c+ abccccd
^ ^
c+?c+ abccccd
^^^ ^ [pass]
c+?c+ abccccd
^^ ^^^ Matched "cccc"!
(c+? -> @c; c+ -> @c)
X{n}
和X{n}?
之间,几乎没有差异;大多数引擎在内部优化了不情愿的旗帜。这是因为惰性构造仅在匹配是动态时才适用,其中引擎可以对量词(需要或贪婪)采用一种方式或另一种方式,但不适用于这种情况。查看regex101,一个功能完善的正则表达式引擎,附带说明和调试器日志,以显示指针步骤。 另请阅读The Stack Overflow Regex Reference!
答案 1 :(得分:3)
[0-9]{2}
与[0-9]{2}?
之间存在差异。
贪婪匹配和懒惰匹配(添加?
)之间的区别与回溯有关。正则表达式引擎构建为匹配文本(从左到右)。因此,当您要求表达式匹配一系列字符时,它是合乎逻辑的,它会尽可能多地匹配。
假设我们有字符串acac123
。
如果我们使用[a-z]+c
(+
代表1次重复或{1,}
)的贪婪匹配:
[a-z]+
与acac
匹配,在1
c
,但在1
aca
和c
如果我们使这个懒惰([a-z]+?c
),我们将获得不同的响应(在此情况下)并且效率更高:
[a-z]+?
会匹配a
,但请停止,因为它会看到下一个字符与表达式的其余部分匹配c
c
会匹配,成功匹配a
和c
(没有回溯)现在您可以看到X{#}
和X{#}?
之间存在无差异,因为{#}
不是范围,甚至贪婪的匹配也不会体验任何回溯。 Lazily匹配通常与*
(0+重复或{0,}
)或+
一起使用,但也可以与范围{m,n}
一起使用(其中n
是可选的)。
当您想要匹配尽可能少的字符时,这是必不可少的,当您想要填充字符串{{1时.*?
时,您通常会在表达式中看到foo.*?bar
}})。然而,很多时候,懒惰匹配是坏/低效正则表达式的一个例子。很多人会像foo bar filler text bar
那样匹配双引号内的所有内容,当你可以通过编写foo:"(.*?)"
这样的表达式来匹配任何但 {{1} }第
最后一点,foo:"([^"]+)"
通常表示“可选”或匹配"
次。 ?
只会在范围({0,1}
,?
,{m,n}
或其他*
)上使用时才会使匹配变得懒惰。这意味着+
不会使?
变得懒惰(因为我们已经说X?
毫无意义),但它将是可选的。但是,你可以做一个懒惰的“可选”匹配:X
将懒惰地匹配0-1次。