跳过正则表达式可选组

时间:2013-11-19 09:35:52

标签: c# regex optional regex-group

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

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组不是可选的,我会得到预期的结果?

3 个答案:

答案 0 :(得分:1)

为什么它不起作用

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

(?<A>.*?)将在第一次尝试时匹配空字符串(因为这就是表达式的含义:如果需要,则为空字符串或更多字符串。)

然后我们在B之后立即进行组BEGIN,因为此处没有START,整个内部组将失败,并且将跳过可选组。

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

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

示例解决方案

如果不允许START / STOP,则可以使用简单的解决方案除了在可选组中,您可以使用如下表达式:

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

模式中较早的构造优先于模式中的构造,而惰性量词(*?)优先考虑较短的匹配。因此,最佳匹配始终是A组不匹配,并且由于START在第一个位置无法匹配,因此将跳过它。最后,C组会占用字符串的其余部分,因为END不是可选的。

请改用:

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

它会强制A组尽可能多地吃,直到B的第一个匹配(如果存在)为止。