?:,?有什么区别?和?=在正则表达式中?


106

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

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

我尝试在简单的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]+)*

请告诉我们您的测试案例。他们不应给出相同的结果。
Bergi 2012年

@ sepp2k,在少数情况下,其结果相似,问题中提到其中之一。
RK Poddar

@Bergi,我用随机数据进行了测试,包含英文单词,电话号码,网址,电子邮件地址,电话号码等。
RK波达

4
@RKAgarwal啊,我明白你在那里做了什么。您*在组之后添加了a ,因此将其忽略。
sepp2k 2012年

注意:您只能在括号的开头使用它们,并且括号形成一个捕获组(不同的括号集提取文本的不同部分)。
瑞安·泰勒

Answers:


150

?=和之间的区别?!是,前者要求给定表达式匹配,而后者则要求匹配。例如,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”的捕获。


78
?:  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,以获取有关正则表达式中超前的很好的教程和示例。


15
但是JavaScript并不了解。
Bergi 2012年

1
对于一般的正则表达式,这是更完整的。
Yan Yang

/(?<= ^ a)b /在javascript中为我工作!互联网上似乎没有教程供您使用Javascript进行回顾。
Y. Yoshii

只有最新版本的浏览器才开始支持JS中的落后功能
-anubhava

– anubhava我不知道使用纯正则表达式可以替代/(?<= ^ a)b /。也许可以,但是我必须依靠回调函数。
Y. Yoshii

21

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

  • () 捕获组 -括号内的正则表达式必须匹配,并且匹配项将创建捕获组
  • (?:) 非捕获组 -括号内的正则表达式必须匹配,但不创建捕获组
  • (?=) 积极向前看 -断言正则表达式必须匹配
  • (?!) 负面展望 -断言不可能匹配正则表达式

让我们将q(u)i退出q匹配q并且捕获组u匹配u。在捕获组中进行匹配并创建捕获组。因此,引擎继续运行i。并i会匹配。最后一次比赛尝试成功。qui被匹配,并且一个捕获组与u创建。

让我们将q(?:u)i退出。同样,q匹配q,非捕获组u匹配u。从非捕获组进行匹配,但未创建捕获组。因此,引擎继续运行i。并i会匹配。最后一次比赛尝试成功。qui被匹配

让我们将q(?=u)i退出。前瞻为正,后跟另一个标记。同样,q匹配qu匹配ü。同样,必须取消前瞻的匹配,因此引擎从i字符串中退回到u。前瞻成功,因此引擎继续运行i。但i不能匹配。因此,此匹配尝试失败。

让我们将q(?=u)u退出。前瞻为正,后跟另一个标记。同样,q匹配qu匹配ü。前瞻的匹配项必须舍弃,因此引擎将从u字符串中的步骤退回到u。前瞻成功,因此引擎继续运行u。并且u会匹配。因此,此匹配尝试成功。匹配

让我们将q(?!i)u退出。即使在这种情况下,超前也是正的(因为i不匹配),并且后面跟随另一个标记。同样,q匹配qi不匹配ü。前瞻的匹配项必须舍弃,因此引擎将从u字符串中的步骤退回到u。前瞻成功,因此引擎继续运行u。并且u会匹配。因此,此匹配尝试成功。匹配

因此,总而言之,前瞻组和非捕获组之间的真正区别在于,如果您只想测试存在性或测试并保存匹配项。捕获组非常昂贵,因此请谨慎使用。


> 因此,引擎从字符串中的i返回到u。前瞻成功,因此引擎继续执行i。但我无法与您相提并论,这完全令人困惑。如果提前,为什么要退后一步
格林

1
@Green要了解前瞻和其他环顾四周结构的一件重要事情是,尽管它们通过动作来查看其子表达式是否能够匹配,但它们实际上并不“消耗”任何文本。这可能有点令人困惑
freedev

7

尝试foobar与此匹配:

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

第一个正则表达式将匹配并返回“ bar”作为第一个子匹配- (?=b)与“ b”匹配,但不使用它,而是将其保留在以下括号中。

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

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


0

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


0

这是真正的区别:

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

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

如果您不在乎“?:”或“?=”,“ ?:”和“?=”之后的内容,则相同。两者都可以使用。

但是,如果您需要这些内容以进行进一步处理(不仅要与整个过程匹配,在这种情况下,您可以简单地使用“ a(b)”),而必须使用“?=”。原因“?:”将通过它消失。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.