替换第 1 组 Java 正则表达式而不替换整个正则表达式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38296673/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:11:19  来源:igfitidea点击:

Replace group 1 of Java regex with out replacing the entire regex

javaregex

提问by Aditya

I have a regex pattern that will have only one group. I need to find texts in the input strings that follows the pattern and replace ONLY the match group 1. For example I have the regex pattern and the string to be applied on as shown below. The replacement string is "<---->"

我有一个只有一组的正则表达式模式。我需要在输入字符串中找到遵循模式的文本并仅替换匹配组 1。例如,我有正则表达式模式和要应用的字符串,如下所示。替换字符串为“<---->”

Pattern p = Pattern.compile("\w*(lan)\w+");
Matcher m = p.matcher("plan plans lander planitia");

The expected result is

预期的结果是

plan p<--->s <--->der p<--->itia

I tried following approaches

我尝试了以下方法

    String test = "plan plans lander planitia";
    Pattern p = Pattern.compile("\w*(lan)\w+");
    Matcher m = p.matcher(test);
    String result = "";
    while(m.find()){
        result = test.replaceAll(m.group(1),"<--->");
    }
    System.out.print(result);

This gives result as

这给出了结果

p<---> p<--->s <--->der p<--->itia

Another approach

另一种方法

    String test = "plan plans lander planitia";
    Pattern p = Pattern.compile("\w*(lan)\w+");
    Matcher m = p.matcher(test);
    String result = "";
    while(m.find()){
        result = test.replaceAll("\w*(lan)\w+","<--->");
    }
    System.out.print(result);

Result is

结果是

plan <---> <---> <--->

I have gone through thislink. Here the part of the string before the match is always constant and is "foo" but in my case it varies. Also I have looked at thisand thisbut I am unable to apply any on the solutions given to my present scenario.

我已经通过这个链接。这里匹配之前的字符串部分始终是常量并且是“foo”,但在我的情况下它会有所不同。我也看过这个这个,但我无法将任何应用于我当前场景的解决方案。

Any help is appreciated

任何帮助表示赞赏

采纳答案by Wiktor Stribi?ew

You need to use the following pattern with capturing groups:

您需要对捕获组使用以下模式:

(\w*)lan(\w+)
^-1-^   ^-2-^

and replace with $1<--->$2

并替换为 $1<--->$2

See the regex demo

查看正则表达式演示

The point is that we use a capturing group around the parts that we want to keep and just match what we want to discard.

关键是我们在我们想要保留的部分周围使用了一个捕获组,并且只匹配我们想要丢弃的部分。

Java demo:

Java演示

String str = "plan plans lander planitia";
System.out.println(str.replaceAll("(\w*)lan(\w+)", "<--->"));
// => plan p<--->s <--->der p<--->itia

If you need to be able to replace the Group 1 and keep the rest, you may use the replace callback method emulation with Matcher#appendReplacement:

如果您需要能够替换第 1 组并保留其余部分,您可以使用替换回调方法模拟Matcher#appendReplacement

String text = "plan plans lander planitia";
String pattern = "\w*(lan)\w+";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(text);
StringBuffer sb = new StringBuffer();
while (m.find()) {
    m.appendReplacement(sb, m.group(0).replaceFirst(Pattern.quote(m.group(1)), "<--->"));
}
m.appendTail(sb); // append the rest of the contents
System.out.println(sb.toString());
// output => plan p<--->s <--->der p<--->itia

See another Java demo

查看另一个 Java 演示

Here, since we process a match by match, we should only replace the Group 1 contents once with replaceFirst, and since we replace the substring as a literal, we should Pattern.quoteit.

在这里,由于我们逐个处理匹配,我​​们应该只用 替换 Group 1 的内容一次replaceFirst,并且由于我们将子字符串替换为文字,我们应该Pattern.quote这样做。

回答by Sebastian Proske

While Wiktors explanation of the use of capturing groups is completely correct, you could avoid using them at all. The \\w*at the start of your pattern seems irrelevant, as you want to keep it anyways, so we can simply leave it out of the pattern. The check for a word-character after lancan be done using a lookahead, like (?=\w), so we actually only match lanin a pattern like "lan(?=\\w)"and can do a simple replace with "<--->"(or whatever you like).

虽然 Wiktor 对使用捕获组的解释是完全正确的,但您完全可以避免使用它们。在\\w*你的模式的开头似乎无关紧要,只要你想保持它反正,所以我们可以简单地把它从格局。之后的单词字符检查lan可以使用前瞻来完成,比如(?=\w),所以我们实际上只匹配lan一个模式 like"lan(?=\\w)"并且可以做一个简单的替换"<--->"(或任何你喜欢的)。

回答by Andreas

To dynamically control the replacement value, use a find()loop with appendReplacement(), finalizing the result with appendTail().

要动态控制替换值,请使用find()with 循环,用appendReplacement()结束结果appendTail()

That way you have full control of the replacement value. In your case, the pattern is the following, and you can get the positions indicated.

这样您就可以完全控制替换值。在您的情况下,模式如下,您可以获得指示的位置。

   start(1)
      ↓  end(1)
      ↓    ↓
  \w*(lan)\w+
  ↑            ↑
start()      end()

You can then extract the values to keep.

然后,您可以提取要保留的值。

String input = "plan plans lander planitia";

StringBuffer buf = new StringBuffer();
Matcher m = Pattern.compile("\w*(lan)\w+").matcher(input);
while (m.find())
    m.appendReplacement(buf, input.substring(m.start(), m.start(1)) +
                             "<--->" +
                             input.substring(m.end(1), m.end()));
String output = m.appendTail(buf).toString();

System.out.println(output);

Output

输出

plan p<--->s <--->der p<--->itia


If you don't like that it uses the original string, you can use the matched substring instead.

如果您不喜欢它使用原始字符串,您可以使用匹配的子字符串。

StringBuffer buf = new StringBuffer();
Matcher m = Pattern.compile("\w*(lan)\w+").matcher("plan plans lander planitia");
while (m.find()) {
    String match = m.group();
    int start = m.start();
    m.appendReplacement(buf, match.substring(0, m.start(1) - start) +
                             "<--->" +
                             match.substring(m.end(1) - start, m.end() - start));
}
String output = m.appendTail(buf).toString();

回答by Ond?ej Men?l

I like others solutions. This is slightly optimalised bulletproof version:

我喜欢其他解决方案。这是稍微优化的防弹版本:

public static void main (String [] args) {
    int groupPosition = 1;
    String replacement = "foo";
    Pattern r = Pattern.compile("foo(bar)");
    Matcher m = r.matcher("bar1234foobar1234bar");
    StringBuffer sb = new StringBuffer();
    while (m.find()) {
        StringBuffer buf = new StringBuffer(m.group());
        buf.replace(m.start(groupPosition)-m.start(), m.end(groupPosition)-m.start(), replacement); 
        m.appendReplacement(sb, buf.toString());
    }
    m.appendTail(sb); 
    System.out.println(sb.toString()); // result is "bar1234foofoo1234bar"
}