Java正则表达式:当预先知道其编号时,如何在特定上下文中反向捕获捕获组

时间:2014-01-29 10:40:24

标签: java regex capturing-group

作为介绍性说明,我知道有关解决正则表达式问题的古老说法,我也了解使用RegEx处理XML的注意事项。但是请跟我说一下......

我正在尝试进行RegEx搜索并替换一组字符。我事先并不知道这个小组的匹配频率,但我想只搜索某个特定的上下文。

一个例子: 如果我有以下字符串"**ab**df**ab**sdf**ab**fdsa**ab**bb"并且我想搜索"ab"并替换为"@ab@",则使用以下正则表达式可以正常工作:

搜索正则表达式:

(.*?)(ab)(.*?)

替换:

$1@$2@$3

我总共得到了四场比赛,正如预期的那样。在每个匹配中,组ID是相同的,因此后引用($ 1,$ 2 ...)也可以正常工作。

但是,如果我现在向字符串添加某个上下文,则上面的正则表达式失败:

搜索字符串:

<context>abdfabsdfabfdsaabbb</context>

搜索正则表达式:

<context>(.*?)(ab)(.*?)</context>

这只会找到第一场比赛。 但即使我在原始正则表达式中添加了非捕获组,它也不起作用("<context>(?:(.*?)(ab)(.*?))*</context>")。

我想要的是第一次搜索中的匹配列表(没有上下文),在每次匹配中,组ID是相同的。

知道如何实现这一目标吗?

1 个答案:

答案 0 :(得分:1)

解决方案

您的要求类似于this question中的要求:匹配并捕获前缀和后缀之间的模式的多个实例。使用this answer of mine中描述的方法:

(?s)(?:<context>|(?!^)\G)(?:(?!</context>|ab).)*ab

根据需要添加捕获组。

买者

请注意,正则表达式仅适用于仅允许仅包含文本的标记。如果标记包含其他标记,则它将无法正常工作。

它还匹配ab标记内的<context>而没有结束标记</context>。如果你想阻止它,那么:

(?s)(?:<context>(?=.*?</context>)|(?!^)\G)(?:(?!</context>|ab).)*ab

说明

让我们打破正则表达式:

(?s)                        # Make . matches any character, without exception
(?:
  <context>
    |
  (?!^)\G
)
(?:(?!</context>|ab).)*
ab

(?:<context>|(?!^)\G)确保我们要么进入新的<context>标记,要么继续上一个匹配并尝试匹配更多的子模式实例。

(?:(?!</context>|ab).)*匹配我们不关心的任何文字(不是ab)并阻止我们越过结束标记</context>。然后我们在最后匹配我们想要ab的模式。