如何匹配而不是捕获正则表达式的一部分?


209

我有一个字符串列表。其中一些具有形式123-...456。可变部分“ ...”可以是:

  • 字符串“ apple”后跟连字符,例如 123-apple-456
  • 字符串“ banana”后跟连字符,例如 123-banana-456
  • 一个空白字符串,例如123-456(请注意,只有一个连字符)

除“ apple”或“ banana”外,其他任何单词均无效。

对于这三种情况,我想分别匹配“ apple”,“ banana”和“”。请注意,我从不希望捕获连字符,但是我总是想匹配它。如果字符串不是上述形式123-...456,则根本没有匹配项。

如何编写正则表达式来做到这一点?假设我有允许先行,后进,环顾和不捕获群组的功能。


此处的主要观察结果是,当您拥有“苹果”或“香蕉”时,还必须具有结尾的连字符,但您不希望将其匹配。并且,当您匹配空白字符串时,您必须没有结尾的连字符。我认为,封装此断言的正则表达式将是正确的。


您想匹配除连字符以外的所有内容吗?
BrunoLM

Answers:


285

不捕获某些内容的唯一方法是使用环顾断言

(?<=123-)((apple|banana)(?=-456)|(?=456))

因为即使使用非捕获组(?:…),整个正则表达式也会捕获其匹配的内容。但这种正则表达式只匹配apple或者banana如果它是由前面123-和后面-456,或者空字符串,如果它的前面有匹配123-和后面456

|Lookaround  |    Name      |        What it Does                       |
-----------------------------------------------------------------------
|(?=foo)     |   Lookahead  | Asserts that what immediately FOLLOWS the |
|            |              |  current position in the string is foo    |
-------------------------------------------------------------------------
|(?<=foo)    |   Lookbehind | Asserts that what immediately PRECEDES the|
|            |              |  current position in the string is foo    |
-------------------------------------------------------------------------
|(?!foo)     |   Negative   | Asserts that what immediately FOLLOWS the |
|            |   Lookahead  |  current position in the string is NOT foo|
-------------------------------------------------------------------------
|(?<!foo)    |   Negative   | Asserts that what immediately PRECEDES the|
|            |   Lookbehind |  current position in the string is NOT foo|
-------------------------------------------------------------------------

1
+1-在这种情况下,可以通过使用组1而不是组0来解决此问题,但这是一个很好的(也是微妙的!)区别。
本·布兰克

@本·布兰克:这绝对取决于如何解释“匹配”和“捕获”。
Gumbo 2010年

8
在JavaScript中不支持,!有一个JS友好的方法会很好,但一点也不差,+ 0.5(向上取整; D)
GiantCowFilms 2015年

喜欢环视断言!这些也可以与Ruby一起使用。
8:51腐烂

完美的解决方案,我喜欢这个
陈广协

15

更新:感谢GermánRodríguezHerrera!

在javascript中尝试: /123-(apple(?=-)|banana(?=-)|(?!-))-?456/

请记住,结果在组1中

Debuggex演示


8

尝试:

123-(?:(apple|banana|)-|)456

这将匹配applebanana或空白字符串,并在其后有一个0或1个连字符。我没有必要成立一个捕获小组,这是错误的。傻我


这是不正确的,因为它与“ 123-coconut-456”匹配。
大卫·斯通

以为您希望它更通用...已修复。
托马斯

5

我修改了答案之一(通过@ op1ekun):

123-(apple(?=-)|banana(?=-)|(?!-))-?456

原因是@ op1ekun的答案也匹配"123-apple456",苹果后面没有连字符。


3

试试这个:

/\d{3}-(?:(apple|banana)-)?\d{3}/

1
这是不正确的,因为它与“ 123-coconut-456”匹配。
大卫·斯通

@david:与您的“香蕉”示例有何不同?
SilentGhost 2010年

@SilentGhost:我只是想捕获applebanana或“”。如我所述,所有其他值均无效。
大卫·斯通

抱歉,在这种情况下:/ \ d {3}-(?:( apple | banana)-)?\ d {3} /

1
此示例显示的是,可以在不使用先行和后行的情况下拥有一个非捕获组。
文斯·潘努乔

0

@Gumbo表达式的一种变体,\K用于重置匹配位置,以防止在匹配中包含数字块。可在PCRE正则表达式中使用。

123-\K(?:(?:apple|banana)(?=-456)|456\K)

火柴:

Match 1  apple
Match 2  banana
Match 3

-3

到目前为止,最简单的方法(适用于python)是'123-(apple|banana)-?456'


1
这将匹配,123-apple456因此不正确。
罗伦(Loren)
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.