捕获的组在正则表达式的可选部分中

时间:2015-02-05 08:42:33

标签: c# regex regex-group

我想在字符串的可选部分中捕获一个组。

例如:

在字符串" firstName:Bill-lastName:Gates" 中,我想捕获2组:

  1. 比尔
  2. 活门
  3. 我使用这个正则表达式:

    firstName:(.*)-lastName:(.*)
    

    但是当lastName-part是可选的时,我仍然希望捕获第一个 group(firstName)。

    我使用了这个正则表达式,使lastName-part可选(在非捕获组中):

    firstName:(.*)(?:-lastName:(.*))?
    

    使用此更新的正则表达式,生成的组为:

    • 当lastName部分不存在时,例如" firstName:Bill" 捕获的组是:

      1. 比尔
      2. / empty string /

    正确

    • 当firstName和lastName部分存在时:" firstName:Bill-lastName:Gates" 组不正确

      1. 比尔-名字:盖茨
      2. /空/

    我认为这与第一个捕获组的贪婪有关,但是当lastName-part是可选的时,如何调整此正则表达式以使正则表达式工作?

2 个答案:

答案 0 :(得分:4)

你是对的,这是关于贪婪的。找到第一个匹配组的分隔符。因此,如果您的名字“never”包含短划线,则只匹配除第一个匹配组的短划线以外的所有内容。

firstName:([^-]*)(?:-lastName:(.*))?

firstName:([^-]*)(?:-lastName:(.*))?

Regular expression visualization

Debuggex Demo

如果找不到这样的分隔符,则需要采用不同的方法。即使您尝试将第一个模式设置为“懒惰”,Regex引擎也始终优先选择更大的匹配,而不是匹配其他可选匹配。

这是因为 lazy matchgroups将匹配满足表达式的第一个字符串(!重要的措辞!)

可能有一个look arrounds选项,但您也可以使用or -statement而不提供可选匹配:

firstName:(.*)-lastName:(.*)|firstName:(.*)

这样,正则表达式引擎会匹配任何一个或,但更喜欢具有2个匹配的模式,因为它首先列出。只有在不适用的情况下,它才会尝试单一匹配。

答案 1 :(得分:2)

即使你已经接受了@ dognose的回答,我向你保证,其中有一些带有破折号的名字(你不想惹恼Jean-Claude van Damme)。我会建议你这样做:

    firstName:((?:(?!-lastName:).)*)(?:-lastName:(.*))?

Regular expression visualization

Debuggex Demo

您可以从可视化中看到(?:(?!-lastName:).)“如果当前位置后面没有' -lastName:',则会捕获另一个字符”