为什么
/<.+?> e/.exec("a <b> c <d> e")
(意外)返回
["<b> c <d> e"]
代替
["<d> e"]
非贪婪的运营商似乎什么都不做......
为什么
/<.+?> e/.exec("a <b> c <d> e")
(意外)返回
["<b> c <d> e"]
代替
["<d> e"]
非贪婪的运营商似乎什么都不做......
"<b> c <d> e"
是一个完全有效的结果。你的正则表达式说“然后匹配<
一些东西,然后> e
” - 这正是你得到的。“直观地”"<d> e"
可能看起来更好的匹配,但是,正则表达式引擎没有直觉,它只是找到第一个匹配的子字符串并停在那里。
当您在两场或多场比赛之间做出选择时,贪婪就会发挥作用 - 这里不是这种情况,因为只有一场比赛。如果您的字符串有两个> e
,则会有所不同:
/<.+> e/.exec("a <b> c <d> e more > e")
> ["<b> c <d> e more > e"]
/<.+?> e/.exec("a <b> c <d> e more > e")
> ["<b> c <d> e"]
使它变得非贪婪,您正在经历的?
行为正在发生,因为您没有告诉它结束尝试匹配>
不属于> e
. 目前;
/<.+?> e/
<
>
或行尾
null
>
> e
,则完全匹配2
请记住,.+
将愉快地匹配>
、 空格和字母,所以这些被包括在内。看起来你想要
/<[^>]+?> e/
<
>
>
或找到行尾
null
>
> e
,则完全匹配1
导致
/<[^>]+?> e/.exec("a <b> c <d> e")
// ["<d> e"]
发生这种情况是因为当它遇到>
不属于 的a 时> e
,它知道它的起始位置一定是错误的,所以再次沿着文本继续直到下一个<
。
这可以让你理解惰性操作符的作用:
/<.+?> e/.exec("a <b> c <d> e <f> e")` // -> ["<b> c <d> e", "<f> e"]
/<.+> e/.exec("a <b> c <d> e <f> e")` // -> ["<b> c <d> e <f> e"]
<.+?> e
意思是:一旦<
找到a,就找到第一个 > e
<.+> e
意思是:一旦<
找到a,找到最后一个 > e
在您的特定情况下,您可以简单地使用<[^>]+> e
(这会更好,因为更快 - 如果可能,总是更喜欢X[^X]X
符号而不是那个X.*?X
)。
来自正则表达式.info:
理解这一点非常重要:正则表达式导向的引擎将始终返回最左边的匹配,即使稍后可以找到“更好”的匹配。
正则表达式引擎从左边开始遍历字符串,并且对于每个字符,说“我可以从这里找到匹配吗?” 非贪婪运算符永远不会阻止在没有匹配项的情况下找到匹配项,因此引擎将继续尝试,这意味着当它从第一个开始检查时<
,它会找到匹配项并立即返回(没有永远检查从 second 开始的匹配<
,因为它没有那么远)。
为了匹配你想要的,一组尖括号后跟一个“e”,你只需确保>
中间没有“
<[^>]+>[ ]e
(请注意,为了清楚起见,空格位于字符类中,而不是因为必须如此。)
通过变得.+
懒惰,模式必须> e
在第一次出现<.+?
. 因为在你的情况下是 substring <b> c
,其余的 pattern> e
还不匹配,所以.+
你的表达式部分继续进行,直到最后> e
部分匹配......
'a <b> c <d> e'
xx//<-- no matches
<//<-- opening < matches, switch to .+?
b//<-- matched by .+
> c//<-- does not match > e, but does match .+
<d// matched by .+
> e// matches rest of expression (> e), the resulting match is:
<b> c <d> e
在您的情况下,我不使用惰性运算符,而是简单地选择:
/(?:<)[^>]+> e/
//or even
/<[^>]+>\s+e/