【问题标题】:replace capturing group替换捕获组
【发布时间】:2011-02-24 15:49:49
【问题描述】:

如果我有一个带有捕获组的正则表达式,例如foo(_+f)。如果我将它与一个字符串匹配,并想用baz 替换第一个捕获组 in all matches 以便

foo___f blah foo________f

转换为:

foobaz blah foobaz

使用标准库似乎没有任何简单的方法可以做到这一点。如果我使用 Matcher.replaceAll() 这将替换整个模式的所有匹配并将字符串转换为

baz blah baz

显然我可以遍历匹配项,存储每个捕获组的开始和结束索引,然后返回并替换它们,但是有没有更简单的方法?

谢谢, 唐

【问题讨论】:

  • 很确定我误解了这个问题,因为我立即想到使用 Matcher.replaceFirst 而不是 replaceAll ...!?

标签: java regex


【解决方案1】:

我想你想要这样的东西?

    System.out.println(
        "foo__f blah foo___f boo___f".replaceAll("(?<=foo)_+f", "baz")
    ); // prints "foobaz blah foobaz boo___f"

这里您只需将整个匹配替换为"baz",但匹配使用后向查找来确保_+f 前面是foo

另见


如果无法进行后视(可能是因为长度不是有限的),那么只需捕获您未替换的内容,并在替换字符串中引用它们。

    System.out.println(
        "fooooo_f boooo_f xxx_f".replaceAll("(fo+|bo+)(_+f)", "$1baz")
    ); // prints "fooooobaz boooobaz xxx_f"

所以在这里我们实际上只替换了 \2 匹配的内容。

【讨论】:

  • 不错的答案,但 OP 似乎已经编辑了匹配模式(g 已删除)。这在很大程度上改变了对这个问题的看法。我建议相应地更新您的答案。
  • 第二个建议很简单,很有效,我自己应该想到的,不需要我学习环视:)
  • 是的,我更新了问题中的模式以试图澄清。抱歉,如果它搞砸了您的回复。
  • @Don:lookarounds 很棒,例如:stackoverflow.com/questions/2559759/…
【解决方案2】:

因此,我认为这些答案中的任何一个都不适用于以下问题的更抽象案例,这是我自己遇到的问题,因此我编写了一些适用于更一般情况的代码:

/**
 * 
 * @param regex  Pattern to find in oldLine. Will replace contents in ( ... ) - group(1) - with newValue
 * @param oldLine  Previous String that needs replacing
 * @param newValue  Value that will replace the captured group(1) in regex
 * @return
 */
public static String replace(String regex, String oldLine, String newValue)
{
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(oldLine);
    if (m.find())
    {
        return m.replaceAll(replaceGroup(regex, newValue));
    }
    else
    {
        throw new RuntimeException("No match");
    }
}

/**
 * Replaces group(1) ( ... ) with replacement, and returns the resulting regex with replacement String
 * @param regex  Regular expression whose parenthetical group will be literally replaced by replacement
 * @param replacement  Replacement String
 * @return
 */
public static String replaceGroup(String regex, String replacement)
{
    return regex.replaceAll("\\(.*\\)", replacement);
}

在您的示例中,它完全按照您的描述进行:

String regex = "foo(_+f)";
String line = "foo___f blah foo________f";
System.out.println(FileParsing.replace(regex, line, "baz"));

打印出来:

foobaz blah foobaz

【讨论】:

    【解决方案3】:
    p = Pattern.compile("foo(g.*?f)");
    m = p.matcher("foog___f blah foog________f");
    s = m.replaceAll("foobaz");//replace with foobaz instead of just baz
    System.out.println(s);//foobaz blah foobaz
    

    【讨论】:

    • 不,我正在尝试替换所有匹配项中的捕获组
    • Amarghosh 的 sn-p 会做什么。在匹配“foo”的同时,它也被包含在替换字符串中,这意味着任何实例,如 foo_f、foo____f、foo__f 等,都会变成 foobaz。
    • @Don 更新了代码供您测试。正如@JAB 提到的,我也将 foo 包含在替换字符串中。而且您发布的原始正则表达式很贪心,您的问题还不够清楚 - 这就是为什么我问您是否正在寻找惰性量词。
    【解决方案4】:

    这里是不是很近……

    String[] s = {"foo___f blah foo________f", 
        "foo___f blah goo________f"};
    for(String ss: s)
    System.out.println(ss.replaceAll("(foo)(_+)f", "$1baz"));
    

    即,也为“foo”添加一个捕获组。否则一个简单的替换将是

    "foo___f blah foo________f".replaceAll("(_+)f", "baz")
    

    【讨论】:

      猜你喜欢
      • 2017-04-08
      • 2021-02-13
      • 2017-10-13
      • 2011-10-09
      • 2017-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-26
      相关资源
      最近更新 更多