我正在尝试捕获所需组内的可选组。到目前为止这是我的正则表达式:
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组不是可选的,我会得到预期的结果?
答案 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
的第一个匹配(如果存在)为止。