173

我搜索了这些表达的含义,但无法理解它们之间的确切区别。

这就是他们所说的:

  • ?:匹配表达式但不捕获它。
  • ?=匹配后缀,但将其从捕获中排除。
  • ?!如果后缀不存在则匹配。

我尝试在简单的 RegEx 中使用这些并得到了类似的结果。

例如:以下 3 个表达式给出了非常相似的结果。

  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?!\.[a-zA-Z0-9]+)*
  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?=\.[a-zA-Z0-9]+)*
  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9]+)*
4

6 回答 6

234

?=和之间的区别在于?!前者要求给定的表达式匹配,而后者要求它匹配。例如a(?=b)将匹配“ab”中的“a”,但不匹配“ac”中的“a”。而a(?!b)将匹配“ac”中的“a”,但不匹配“ab”中的“a”。

和之间的区别在于?:?=?=从整个匹配中排除了表达式,而?:只是不创建捕获组。所以例如a(?:b)将匹配“abc”中的“ab”,而a(?=b)只会匹配“abc”中的“a”。a(b)将匹配“abc”中的“ab”创建包含“b”的捕获。

于 2012-05-29T18:43:02.283 回答
122
?:  is for non capturing group
?=  is for positive look ahead
?!  is for negative look ahead
?<= is for positive look behind
?<! is for negative look behind

请在此处查看:http ://www.regular-expressions.info/lookaround.html以获得非常好的教程和正则表达式前瞻示例。

于 2012-05-29T18:38:48.770 回答
47

为了更好地理解,让我们应用三个表达式加上一个捕获组并分析每个行为。

  • () 捕获组- 括号内的正则表达式必须匹配并且匹配创建一个捕获组
  • (?:) 非捕获组- 括号内的正则表达式必须匹配但不创建捕获组
  • (?=) 积极的前瞻- 断言正则表达式必须匹配
  • (?!) 负前瞻- 断言不可能匹配正则表达式

让我们申请q(u)i退出。匹配q并且捕获组匹配u。获取捕获组内的匹配并创建捕获组。所以引擎继续。并将匹配i。最后一次匹配尝试是成功的。qui匹配并创建了一个带有u的捕获组。
qu

i
i

让我们申请q(?:u)i退出。同样,匹配q并且非捕获组匹配u。来自非捕获组的匹配被取走,但不创建捕获组。所以引擎继续。并将匹配i。最后一次匹配尝试是成功的。qui匹配。
qu

i
i

让我们申请q(?=u)i退出。前瞻是肯定的,后面跟着另一个令牌。同样,匹配q并匹配u。但是来自前瞻的匹配必须被丢弃,因此引擎从字符串中退回到u。鉴于前瞻成功,引擎继续运行。但不能匹配u。所以这个匹配尝试失败了

qu
i
i
i

让我们申请q(?=u)u退出。前瞻是肯定的,后面跟着另一个令牌。同样,匹配q并匹配u。但是来自前瞻的匹配必须被丢弃,因此引擎从字符串中退回到u。鉴于前瞻成功,引擎继续运行。并且会匹配u。所以这个匹配尝试是成功的。qu匹配。

qu
u
u
u

让我们申请q(?!i)u退出。即使在这种情况下,前瞻也是肯定的(因为不匹配),并且后面跟着另一个令牌。同样,匹配q并且不匹配u。来自前瞻的匹配必须被丢弃,因此引擎从字符串中退回到u。鉴于前瞻成功,引擎继续运行。并且会匹配u。所以这个匹配尝试是成功的。qu匹配。
i
qi
u
u
u

因此,总而言之,前瞻组和非捕获组之间的真正区别在于您是否只想测试存在或测试并保存匹配。

但是捕获组很昂贵,因此请明智地使用它。

于 2016-08-15T22:20:14.630 回答
8

尝试匹配foobar这些:

/foo(?=b)(.*)/
/foo(?!b)(.*)/

第一个正则表达式将匹配并将返回“bar”作为第一个子匹配 -(?=b)匹配“b”,但不使用它,将其留给后面的括号。

第二个正则表达式将不匹配,因为它期望“foo”后面跟着不同于“b”的东西。

(?:...)与 simple 具有完全相同的效果(...),但它不会将该部分作为子匹配返回。

于 2012-05-29T18:42:00.527 回答
1

理解断言的最简单方法是将它们视为插入正则表达式的命令。当引擎运行到一个断言时,它会立即检查断言所描述的条件。如果结果为真,则继续运行正则表达式。

于 2020-05-09T12:44:02.300 回答
0

这是真正的区别:

>>> re.match('a(?=b)bc', 'abc')
<Match...>
>>> re.match('a(?:b)c', 'abc')
<Match...>

# note:
>>> re.match('a(?=b)c', 'abc')
None

如果你不关心“?:”或“?=”之后的内容,“?:”和“?=”是一样的。两者都可以使用。

But if you need those content for further process(not just match the whole thing. In that case you can simply use "a(b)") You have to use "?=" instead. Cause "?:"will just through it away.

于 2020-05-24T23:18:42.380 回答