【问题标题】:regex optional group is skipped正则表达式可选组被跳过
【发布时间】:2013-11-19 09:35:52
【问题描述】:

我正在尝试在必需组中捕获可选组。到目前为止,这是我的正则表达式:

BEGIN
(?<body>
     (?<A>.*?)               # in my regex just .*?
     (?<B>START.*?STOP)?
     (?<C>.*?)               # in my regex just .*?
)
END

输入:

junk1 BEGIN junk2 START content STOP junk3 END junk4

我明白了:

match: 'BEGIN junk2 START content STOP junk3 END' # ok
group 'body':  ' junk2 START content STOP junk3 ' # ok
group 'A': ''                                     # expected: ' junk2 '
group 'B': not found                              # expected: 'START content STOP'
group 'C': ' junk2 START content STOP junk3 '     # expected: ' junk3 '

A 组和 C 组仅供参考

为什么即使有正确的数据,B组也不匹配,如果B组不是可选的,我会得到预期的结果?

【问题讨论】:

  • 你的意思是在(?&lt;B&gt;START.*?END)?中写STOP而不是END,对吧?

标签: c# regex optional regex-group


【解决方案1】:

为什么它不起作用

您必须对正则表达式引擎和backtracking 的工作原理有一些基本的了解。在这种情况下,它是这样的:

(?&lt;A&gt;.*?) 组将在第一次尝试时匹配空字符串(这就是表达式的含义:如果需要,空字符串或更多)。

然后我们就在BEGIN之后进入B组,因为这里没有START,整个内部组将失败,并且可选组将被跳过。

C 将匹配空字符串。然后我们尝试匹配END,不匹配。因此,正则表达式引擎将尝试回溯最后一个量词。在这种情况下,在组 C 中。它会一直这样做,直到找到匹配项(或尝试之前的量词,直到失败)。

所以我们最终将组 C 扩展到 END,然后整个表达式匹配。

示例解决方案

如果START/STOP 不允许出现在可选组中的 except 中,则可以制定一个简单的解决方案,您可以使用如下表达式:

BEGIN
(?<body>
     (?<A>
          (?: (?!START|STOP) . )*?   # do not match START nor STOP
     )
     (?<B>START.*?STOP)?
     (?<C>
          (?: (?!START|STOP) . )*?   # do not match START nor STOP
     )
)
END

【讨论】:

  • 这个解决方案很完美,谢谢。 - 但是如果正则表达式中的 START 也是正则表达式 - 有没有办法只定义一次 START 正则表达式?
  • @CzBuCHi,在 .NET 正则表达式中无法做到这一点。但如果你愿意,你可以避免重复太多。例如,您可以将旧表达式用于组 A
【解决方案2】:

在 c# 中,模式匹配由正则表达式模式(更多 here)驱动,而不是输入文本。因此,发生的情况是 A 组不需要匹配任何内容,因此决定延迟,B 组不需要匹配任何内容,因此决定延迟,C 组不需要匹配任何内容,但到达正则表达式的结尾。组 C 与输入字符串匹配,并分配您期望在组 B 中的所有内容。如果您使用从右到左的模式匹配,所有内容都将分配给组 A。

【讨论】:

    【解决方案3】:

    模式中较早的构造优先于模式中较晚的构造,惰性量词 (*?) 优先考虑较短的匹配。所以最好的匹配永远是不匹配A 组的任何东西,并且由于START 在第一个位置无法匹配,它将被跳过。最后C 组将吃掉字符串的其余部分,因为END 不是可选的。

    改用这个:

    BEGIN
    (?<body>
        (?<A>.*?)
        (?:
            (?<B>START.*?STOP)
            (?<C>.*?)
        )?
    )
    END
    

    它将强制A 组尽可能多地进食,直到B 的第一场比赛(如果存在)。

    【讨论】:

      猜你喜欢
      • 2010-11-04
      • 2013-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-26
      • 2020-06-24
      • 1970-01-01
      相关资源
      最近更新 更多