在java中替换重复出现的锚定正则表达式组

时间:2016-10-10 13:50:19

标签: java regex

使用Java 7和java.util.regex.Pattern中的默认RegEx实现,给出这样的正则表达式:

^start (m[aei]ddel[0-9] ?)+ tail$

这样的字符串:

start maddel1 meddel2 middel3 tail

是否可以使用锚定的正则表达式获得这样的输出:

start <match> <match> <match> tail

我可以让每个群体都没有这样的锚:

正则表达式:m[aei]ddel[0-9]

StringBuffer sb = new StringBuffer();
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
    matcher.appendReplacement(sb, Matcher.quoteReplacement("<middle>"));
}

问题在于,我正在处理一个非常大的数据集,能够锚定模式将是一个巨大的性能胜利。

然而,当我添加锚点时,我能找到的唯一API需要完整匹配并访问该组的最后一次出现。我的情况我需要验证正则表达式实际匹配(即整个匹配),但在替换步骤中我需要能够访问它自己的每个组。

编辑我想避免在单独的步骤中寻找锚点等变通方法,因为它需要对代码进行更大的更改并将其全部包装在RegExes感觉更优雅。< / p>

3 个答案:

答案 0 :(得分:3)

您可以使用\G

final String regex = "(^start |(?<!^)\\G)m[aei]ddel[0-9] (?=.* tail$)";
final String str = "start maddel1 meddel2 middel3 tail";

String repl = str.replaceAll(regex, "$1<match> ");
//=> start <match> <match> <match> tail

RegEx Demo

\G在上一场比赛结束或第一场比赛的字符串开头处断言位置。

答案 1 :(得分:2)

要一步完成,您需要使用基于\G的正则表达式进行锚定。但是,您还需要一个积极的先行来检查字符串是否以所需的模式结束。

这是一个应该有效的正则表达式:

(^start|(?!\A)\G)\s+m[aei]ddel[0-9](?=(?:\s+m[aei]ddel[0-9])*\s+tail$)

请参阅regex demo

String s = "start maddel1 meddel2 middel3 tail";
String pat = "(^start|(?!\\A)\\G)\\s+(m[aei]ddel[0-9])(?=(?:\\s+m[aei]ddel[0-9])*\\s+tail$)";
System.out.println(s.replaceAll(pat, "$1 <middle>" )); 

请参阅Java online demo

<强>解释

  • (^start|(?!\A)\G) - 在字符串末尾匹配start或上一次成功匹配结束
  • \s+ - 一个或多个空格
  • m[aei]ddel[0-9] - m,然后aei,然后是ddel,然后是1位
  • (?=(?:\s+m[aei]ddel[0-9])*\s+tail$) - 仅限于:
    • (?:\s+m[aei]ddel[0-9])* - 零个或多个1+空格序列和middelN模式
    • \s+ - 一个或多个空格
    • tail$ - tails substring后跟字符串结尾。

答案 2 :(得分:2)

使用\G锚点,对于find方法,您可以这样写:

pat = "\\G(?:(?!\\A) |\\Astart (?=(?:m[aei]ddel[0-9] )+tail\\z))(m\\S+)";

细节:

\\G # position after the previous match or at the start of the string
    # putting it in factor makes fail the pattern more quickly after the last match
(?:
    (?!\\A) [ ] # a space not at the start of the string
                # this branch is the first one because it has more chance to succeed
  |
    \\A start [ ] # "start " at the beginning of the string
    (?=(?:m[aei]ddel[0-9] )+tail\\z) # check the string format once and for all
                                     # since this branch will succeed only once
)
( # capture group 1
    m\\S+ # the shortest and simplest pattern that matches "m[aei]ddel[0-9]"
          # and excludes "tail" (adapt it to your need but keep the same idea)
)

demo