我可以替换Java正则表达式中的组吗?

wok*_*ena 88 java regex replace regex-group

我有这个代码,我想知道,如果我只能替换Java正则表达式中的组(不是所有模式).码:

 //...
 Pattern p = Pattern.compile("(\\d).*(\\d)");
    String input = "6 example input 4";
    Matcher m = p.matcher(input);
    if (m.find()) {

        //Now I want replace group one ( (\\d) ) with number 
       //and group two (too (\\d) ) with 1, but I don't know how.

    }
Run Code Online (Sandbox Code Playgroud)

Cha*_*ick 115

使用$n(其中n是数字)来引用捕获的子序列replaceFirst(...).我假设您想要使用文字字符串"number"替换第一个组,将第二个组替换为第一个组的值.

Pattern p = Pattern.compile("(\\d)(.*)(\\d)");
String input = "6 example input 4";
Matcher m = p.matcher(input);
if (m.find()) {
    // replace first number with "number" and second number with the first
    String output = m.replaceFirst("number $3$1");  // number 46
}
Run Code Online (Sandbox Code Playgroud)

考虑(\D+)第二组而不是(.*). *是一个贪婪的匹配器,并将首先消耗最后一位数字.然后匹配器必须回溯,当它意识到最终(\d)没有任何东西可以匹配时,才能匹配到最后的数字.

  • 如果你想发布一个示例输出本来不错 (7认同)
  • 这适用于第一场比赛,但是如果有很多组并且你用一段时间迭代它们就不会工作(m.find()) (6认同)
  • 我同意 Hugo 的观点,这是实现解决方案的一种糟糕方式......为什么这是公认的答案而不是 acdcjunior 的答案 - 这是完美的解决方案:少量代码,高内聚和低耦合,机会少得多(如果不是没有机会)不必要的副作用...... *叹气*...... (2认同)

acd*_*ior 49

您可以使用Matcher#start(group)Matcher#end(group)构建一个通用的替换方法:

public static String replaceGroup(String regex, String source, int groupToReplace, String replacement) {
    return replaceGroup(regex, source, groupToReplace, 1, replacement);
}

public static String replaceGroup(String regex, String source, int groupToReplace, int groupOccurrence, String replacement) {
    Matcher m = Pattern.compile(regex).matcher(source);
    for (int i = 0; i < groupOccurrence; i++)
        if (!m.find()) return source; // pattern not met, may also throw an exception here
    return new StringBuilder(source).replace(m.start(groupToReplace), m.end(groupToReplace), replacement).toString();
}

public static void main(String[] args) {
    // replace with "%" what was matched by group 1 
    // input: aaa123ccc
    // output: %123ccc
    System.out.println(replaceGroup("([a-z]+)([0-9]+)([a-z]+)", "aaa123ccc", 1, "%"));

    // replace with "!!!" what was matched the 4th time by the group 2
    // input: a1b2c3d4e5
    // output: a1b2c3d!!!e5
    System.out.println(replaceGroup("([a-z])(\\d)", "a1b2c3d4e5", 2, 4, "!!!"));
}
Run Code Online (Sandbox Code Playgroud)

在这里查看在线演示.

  • 这确实应该是公认的答案,它是最完整和“随时可用”的解决方案,不会对随附的代码引入一定程度的耦合。尽管我建议更改其中之一的方法名称。乍一看,它看起来像是第一个方法中的递归调用。 (2认同)

Yar*_*aro 18

对不起击败死马,但它是一种-的怪异,没有人指出这一点 - "是的,你可以,但是这是你如何使用捕获组在现实生活中相反".

如果您按照使用方式使用Regex,解决方案就像这样简单:

"6 example input 4".replaceAll("(?:\\d)(.*)(?:\\d)", "number$11");
Run Code Online (Sandbox Code Playgroud)

或者正如下面的shmosel所指出的,

"6 example input 4".replaceAll("\d(.*)\d", "number$11");
Run Code Online (Sandbox Code Playgroud)

...因为在你的正则表达式中没有充分的理由对小数组进行分组.

您通常不会在要丢弃的字符串部分上使用捕获组,而是在要保留的字符串部分使用它们.

如果你真的想要,你要替换组,你可能就要什么是模板引擎(如胡子,EJS,StringTemplate的,...).


作为好奇的,即使是正则表达式中的非捕获组也只是存在,因为正则表达式引擎需要它们识别并跳过变量文本.例如,在

(?:abc)*(capture me)(?:bcd)*
Run Code Online (Sandbox Code Playgroud)

如果您的输入看起来像"abcabc capture me bcdbcd"或"abc capture me bcd"或者甚至只是"捕获我",那么你需要它们.

或者换句话说:如果文本总是相同的,并且你没有捕获它,那么根本没有理由使用组.

  • 非捕获组是不必要的;`\d(.*)\d` 就足够了。 (2认同)
  • 我不明白这里的“$11”。为什么是 11? (2认同)

mkb*_*mkb 9

通过添加parens来添加第三个组.*,然后用"number" + m.group(2) + "1".替换子序列.例如:

String output = m.replaceFirst("number" + m.group(2) + "1");
Run Code Online (Sandbox Code Playgroud)

  • 实际上,Matcher支持$ 2风格的引用,所以m.replaceFirst("数字$ 21")会做同样的事情. (4认同)
  • 看起来"数字$ 21"将取代第21组,而不是第2组+字符串"1". (2认同)