【问题标题】:Java replace capturing group with different valueJava用不同的值替换捕获组
【发布时间】:2014-04-16 03:38:02
【问题描述】:

在 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” 我怎样才能做到这一点? 感谢您的帮助。

【问题讨论】:

  • 每个地图术语将替换单词出现的任何位置。它可能适用于我的示例。所以一般来说,我想用一些取决于捕获组的值替换匹配部分的捕获组。

标签: java regex


【解决方案1】:

请考虑将Stack Overflow Regular Expressions FAQ 加入书签以供将来参考。那里有一堆特定于 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

【讨论】:

  • 甜蜜!感谢您的投票和绿色的大勾号! :)
【解决方案2】:

如果您只是想匹配出现在 : 之前的单词,则创建该表达式并在地图上迭代会容易得多。

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:与使用正则表达式相比,这种映射迭代是一种更简单、更有效的解决方案。出于某种原因需要正则表达式吗?有更多的上下文会很好。
  • 它更简单,但不是正确的解决方案,例如,如果存在来自“me”->“xyz”的映射,那么“fname:hello”将被替换为“fnaxyz:hello”,这不是我想要什么
  • @PrathikPuthran,给定的解决方案适用于您提供的输入,但如果您需要在单词前留一个空格以确保它是单独的,那么在计算上仍然比正则表达式便宜。
【解决方案3】:

您可以浏览地图的 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

这是否充分回答了您的问题,或者输出是您定义它的方式是否必不可少?

【讨论】:

  • 它最重要的输出就是我想要的样子!
  • 那你可以做str.replaceAll(entry.getKey() + ":", ":" + entry.getValue()); 但这有点小技巧,所以我建议使用不同的方法:)
  • 这不适用于我的情况,因为它替换了第一个“hello”,即使它与正则表达式不匹配
  • 如果你复制它不应该这样做,因为关键是你好,你把它和“:”连接起来,这样就不会匹配你的第一个“你好”
  • 如果存在从“me”到“abc”的映射,您的解决方案将替换“fnaabc:hello”而不是预期的“meme:hello”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-09
  • 2011-02-24
  • 1970-01-01
  • 2021-02-13
  • 2017-05-02
  • 2014-06-19
  • 2010-11-19
相关资源
最近更新 更多