我想知道为什么以下正则表达式适用于某些字符串而不适用于其他字符串:
/^([0-3]+)(?!4|.*5)[0-9]+$/
1151 - >这不符合
1141 - >这确实匹配,但为什么呢?因为我可以认为。*为空,正则表达式变为/^([0-3]+)(?!4|5)[0-9]+$/
我认为我误解了前瞻的方式......
答案 0 :(得分:9)
让我们看一下正则表达式如何逐步解析字符串。
^([0-3]+)(?!4|.*5)[0-9]+$
首先,一些澄清。 (?!4|.*5)
是一个否定的预测,用于检查4
或.*5
是否跟随最后消费的字符。如果是,则当前匹配失败并退回。它也可以写成(?!(4|.*5))
,如果您希望它更清楚|
对它的影响程度。
让我们先来看一下1141
首先,[0-3]+
会消耗尽可能多的字符,因此它会占用11
中的1141
。剩下的是41
。正则表达式现在检查4
是否在当前字符之后,并且由于?!
是否定前瞻,如果找到匹配将失败。由于4
跟随11
,因此匹配失败,正则表达式向后退步并再次尝试。
它不是匹配两个1
,而是现在尝试一次匹配并匹配1
,并留下141
。 ?!4
检查以确保4
是下一个字符,你知道什么,它不在那里。正则表达式因为不匹配而留下负面预测,并继续执行正则表达式的其余部分。 141
与最终[0-9]+
匹配,因此整个 1141
字符串匹配。请记住,环顾四周不会消耗字符。
现在让我们看一下1151
同样的事情发生在上次,11
被消耗,我们剩下51
。现在我们来看看负面预测,然后评估其余的字符串。显然,4
在此字符串中没有位置,所以我们可以忽略它,所以让我们看一下.*5
。
因此,预测.*5
会尝试匹配51
。如果它最终匹配,就像在匹配失败之前一样,正则表达式将退回。现在,如果您完全了解任何正则表达式,很明显.*5
将匹配51
的开头,因为.*
可以评估为空。
所以我们退后一步,现在我们匹配了一个1
而不是两个,我们再次处于负面预测中。
我们目前已消费1
,仍有151
可供选择,并且位于正则表达式的(?!4|.*5)
部分。在这里,4
在我们的字符串中显然是不存在的,所以它不会匹配,所以让我们再看一下.*5
。
.*5
将匹配151
的一部分,因为.*
将使用第一个1
,5
将通过匹配5
来完成}。如果你知道正则表达式,这也应该是显而易见的。
所以我们再次以负面反超进行了比赛,这很糟糕......所以我们再次退后一步。我们没有更多的整数来尝试与[0-3]匹配,因为你不能将0整数与+
匹配,整个字符串都无法与正则表达式匹配。
答案 1 :(得分:2)
1141
匹配,因为正则表达式引擎可以回匹配11
与[0-3]+
匹配,只匹配第一个1
,剩下的数字将由[0-9]+
。
由于第一个1
之后的下一个字符是1
而不是4
,所以仅查看下一个字符的否定预测不会阻止匹配。< / p>
1151
不匹配,因为添加了.*
的否定前瞻会阻止它。
在.*
之前添加了5
,现在预测就意味着'如果下一个字符为4
则不匹配,或者在下一个字符为任意数字之后字符为5
'(忽略换行符)。
因此,即使引擎回溯使[0-3]+
与1
的第一个1151
匹配,字符串前面仍然有一个5
,所以匹配是防止。
请记住,前瞻和后视是零宽度。
答案 2 :(得分:0)
如果你想让它匹配4或5,最好的选择是
/^[0-3]+[45][0-9]+$/
但如果没有更好地解释它应该做什么,那么很难提出更多的建议......
答案 3 :(得分:0)
那是什么样的正则表达式?
/ ^([0-3] +)的(?4 |。* 5)强> [0-9] + $ /
老实说,我认为它匹配1141而不是1151的唯一方法是将正则表达式的突出显示部分评估为NOT 4 or .* followed by 5
。如果是这种情况,那么正则表达式引擎将无法找到1141
的匹配,因为它将匹配4,但会错过5以使内部匹配完成。
但是,通常情况下,轮换将被理解为4
或.*5
- 这仍然不等于4或5,因为表达式.*
可以证明是非常强大的引擎想要匹配工作。
你在测试表达式的是什么?