Java替换捕获组为不同的值

3

在Java中,我想仅替换匹配部分中的捕获组,并且要替换的值取决于捕获组。

例如:

String str = "fname:hello hello:world ffff:off";
Map<String, String> mapping = new HashMap<String, String>();
dat.put("fname", "meme");
dat.put("hello", "below");
dat.put("ffff", "ssss");
Pattern pat = Pattern.compile("([a-zA-Z_]+):");

在上述代码中,我想将模式“pat”中捕获组部分用在“mapping”中找到的相应映射替换。 即,在替换后,“str”字符串应该被转换为“meme:hello below:world ssss:off”。 我该如何实现这一点? 感谢您的帮助。

每个映射术语都将替换单词出现的位置。这可能适用于我的示例。因此,通常我想使用某些值替换匹配部分的捕获组,该值取决于捕获组。 - Bourne
3个回答

5
请考虑收藏 Stack Overflow 正则表达式常见问题解答 以备将来参考。其中有很多关于 Java 的专业信息,特别是在“特定语言信息”部分。
这个有效:
import  java.util.Map;
import  java.util.HashMap;
import  java.util.regex.Pattern;
import  java.util.regex.Matcher;

public class Replacement  {
   public static final void main(String[] ignored)  {

      String str = "fname:hello hello:world ffff:off";
      Map<String, String> mapping = new HashMap<String, String>();
      mapping.put("fname", "meme");
      mapping.put("hello", "below");
      mapping.put("ffff", "ssss");
      Pattern pat = Pattern.compile("([a-zA-Z_]+):");

      Matcher m = pat.matcher(str);


      StringBuffer sb = new StringBuffer();
      while(m.find())  {
         String rplcWith = mapping.get(m.group(1));
         m.appendReplacement(sb, rplcWith + ":");
      }
      m.appendTail(sb);

      System.out.println(sb);
   }
}

输出:

[C:\java_code\]java Replacement
meme:hello below:world ssss:off

太好了!感谢您的点赞和大大的绿色勾号! :) - aliteralmind

1
如果您只是想匹配一个单词是否出现在:之前,那么更容易的方法是创建该表达式并遍历地图。
import java.util.*;

public class Main{ 
    public static void main(String[] args) {
        String str = "fname:hello hello:world ffff:off";
        Map<String, String> mapping = new HashMap<String, String>();
        mapping.put("fname", "meme");
        mapping.put("hello", "below");
        mapping.put("ffff", "ssss");

        for (String key: mapping.keySet()) 
            str = str.replace(key + ":", mapping.get(key)+":");
        System.out.println(str);
    }
}

这很简单,但足以得到您想要的输出结果:
meme:hello below:world ssss:off

@PrathikPuthran:这个地图迭代比使用正则表达式更简单、更高效。是否有某些原因需要使用正则表达式?如果能提供更多上下文信息就更好了。 - aliteralmind
它更简单,但不是正确的解决方案。例如,如果存在从“me”->“xyz”的映射,则“fname:hello”将被替换为“fnaxyz:hello”,这不是我想要的。 - Bourne
@PrathikPuthran,给定的解决方案适用于您提供的输入,但是如果您需要在单词前面加一个空格以确保它独立存在,那么这仍然比正则表达式更便宜。 - merlin2011

0
你可以遍历你的 map 的 entrySet,并将所有键的实例替换为它们关联的值。
for (Entry<String, String> entry : mapping.entrySet()) {
    str.replaceAll(entry.getKey(), entry.getValue();
}

然而,这将产生一个不同于您期望的输出字符串,因为单词“hello”出现了两次

所以,您将得到meme:below below:world ssss:off而不是meme:hello below:world ssss:off

这个回答是否充分回答了您的问题,或者输出如何定义对您来说很重要?


它的输出非常重要,正如我所期望的那样! - Bourne
然后你可以使用 str.replaceAll(entry.getKey() + ":", ":" + entry.getValue()); 但那有点像是一个hack,所以我建议采用不同的方法 :) - Eddie Curtis
这对我的情况不适用,因为它会替换第一个“hello”,即使它不匹配正则表达式。 - Bourne
1
如果你复制正确了,它就不应该出现这种情况,因为关键字是“hello”,而你正在将其与“:”连接起来,所以它不会匹配你的第一个“hello”。 - Eddie Curtis
如果存在从“me”到“abc”的映射,您的解决方案将替换“fnaabc:hello”,而不是预期的“meme:hello”。 - Bourne
如果在开头添加\b单词边界,它应该可以工作:str.replaceAll("\\b" + entry.getKey() + ":", ... - aliteralmind

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接