正则表达式捕获输入块中间的可选组
Posted
技术标签:
【中文标题】正则表达式捕获输入块中间的可选组【英文标题】:Regex to capture an optional group in the middle of a block of input 【发布时间】:2009-01-03 02:13:26 【问题描述】:我遇到了一个看似非常简单的 RegEx 问题,但我无法让它工作。
假设我有这样的输入:
Some text %interestingbit% lots of random text lots and lots more %anotherinterestingbit%
Some text %interestingbit% lots of random text OPTIONAL_THING lots and lots more %anotherinterestingbit%
Some text %interestingbit% lots of random text lots and lots more %anotherinterestingbit%
输入中有很多重复的块,在每个块中我想捕捉一些始终存在的东西(%interestingbit% 和 %anotherinterestingbit%),但也有一些文本可能会或可能不会出现在-在它们之间(OPTIONAL_THING),如果它在那里,我想捕捉它。
像这样的 RegEx 只匹配其中包含 OPTIONAL_THING 的块(并且命名的捕获有效):
%interestingbit%.+?((?<OptionalCapture>OPTIONAL_THING)).+?%anotherinterestingbit%
所以看起来这只是让整个组可选的问题,对吧?这就是我尝试过的:
%interestingbit%.+?((?<OptionalCapture>OPTIONAL_THING))?.+?%anotherinterestingbit%
但我发现虽然这匹配所有 3 个块,但命名捕获(OptionalCapture)在所有块中都是空的!我如何让它发挥作用?
请注意,每个块中可以有很多文本,包括换行符,这就是我输入“.+?”的原因。而不是更具体的东西。我正在使用 .NET 正则表达式,使用 The Regulator 进行测试。
【问题讨论】:
【参考方案1】:我的想法与 Niko 的想法相似。但是,我建议放置第二个 .+?在可选组内而不是第一个,如下:
%interestingbit%.+?(?:(?<optionalCapture>OPTIONAL_THING).+?)?%anotherinterestingbit%
这避免了不必要的回溯。如果第一个 .+?位于可选组内,并且搜索字符串中不存在 OPTIONAL_THING,正则表达式在到达字符串末尾之前不会知道这一点。然后它需要回溯,也许相当长,以匹配 %anotherinterestingbit%,正如你所说,它将永远存在。
此外,由于 OPTIONAL_THING 存在时,它始终位于 %anotherinterestingbit% 之前,因此它之后的文本实际上也是可选的,并且更自然地适合可选组。
【讨论】:
【参考方案2】:为什么要多出一组括号?
试试这个:
%interestingbit%.+?(?<OptionalCapture>OPTIONAL_THING)?.+?%anotherinterestingbit%
或者也许这会起作用:
%interestingbit%.+?(?<OptionalCapture>OPTIONAL_THING|).+?%anotherinterestingbit%
在此示例中,该组捕获 OPTIONAL_THING,或者什么都不捕获。
【讨论】:
不,抱歉,这些都不起作用。它们与我的正则表达式相同,组是可选的 - 所有 3 个块都匹配,但没有捕获 OPTIONAL_THING。 @Evgeny,你确定.+?使通配符“不贪心”?也许你可以试试 .*?而是。 @Evgeny,当您将命名组转换为非命名/编号组时,正则表达式的任何工作是否按预期工作?此外,另一种选择是执行类似 /(currently working regex here|regex without OPTIONAL_THING here)/. @strager,不,无论是否命名都没有区别。大|也不起作用,因为它为上述输入生成 2 个匹配项,第一个匹配项是从第一个块的开头到第二个块的结尾。 对我来说,问题似乎出在第一个非贪婪匹配模式上。您实际上匹配到 OPTIONAL_THING 或什么都没有,所以第一个 .+?立即找到“无”并停止匹配。因为 OPTIONAL_THING 不是紧随其后,第二个 .+?匹配输入的其余部分。对吧..?【参考方案3】:试试这个:
%interestingbit%(?:(.+)(?<optionalCapture>OPTIONAL_THING))?(.+?)%anotherinterestingbit%
首先有一个非捕获组匹配.+OPTIONAL_THING
或不匹配。如果找到匹配项,则里面有一个命名组,它会为您捕获OPTIONAL_THING
。其余部分使用.+?%anotherinterestingbit%
捕获。
[编辑]:我为其他捕获组添加了几个括号,因此现在捕获的组与以下内容匹配:
$1:OPTIONAL_THING 之前的文本或什么都没有 $2 或 $optionalCapture:OPTIONAL_THING 或什么都没有 $3 : OPTIONAL_THING 之后的文本,或者如果没有找到 OPTIONAL_THING,则为 %interestingbit% 和 %anotherinterestingbit% 之间的全文这是你要找的三个匹配项吗?
【讨论】:
抱歉,这与使用一个大的“|”有同样的问题- 第一个匹配包含两个块,所以总共只有 2 个匹配,而不是 3 个。 Oooops.. 在注意到我的答案上方有一个新答案之前编辑了我的答案。关于 Stack Overflow 的另一件事——答案不是按时间顺序排列的......以上是关于正则表达式捕获输入块中间的可选组的主要内容,如果未能解决你的问题,请参考以下文章