如何在 java 中使用正则表达式替换标签 <> 中所有出现的字符串

how to replace all occurrences of a string inside tags <> using regex in java

我在标签中有一个字符串。例如:“我是 src scr 客户

我想用“abc”替换“src”。我使用以下正则表达式来替换:- replacAll("(.?)src(.?)"),"$1"+"abc"+"$2"); 但它仅替换第一次出现的字符串,即输出为“I am abc src customer

我希望输出为“我是 abc abc 客户”。

我不想使用匹配器模式。有没有使用 replaceAll() 的解决方案?请帮忙。

我们可以在这里尝试使用正式的正则表达式模式匹配器。匹配模式 <abc~a>(.*?)<abc~a>,并为每个匹配附加标签,其中 src 替换为 abc。这是一个示例代码:

String input = "Here is a src <abc~a>I am an src customer<abc~b> also another src here.";
Pattern p = Pattern.compile("<abc~a>(.*?)<abc~b>");
Matcher m = p.matcher(input);
StringBuffer buffer = new StringBuffer();
  
while(m.find()) {
    String replace = "<abc~a>" + m.group(1).replaceAll("\bsrc\b", "abc") + "<abc~b>";
    m.appendReplacement(buffer, replace);
}
m.appendTail(buffer);

System.out.println(buffer.toString());

这会打印:

Here is a src <abc~a>I am an abc customer<abc~b> also another src here.

请注意,在许多其他语言中,我们可以使用正则表达式回调函数。但是核心 Java 不支持这个功能,所以我们必须遍历整个输入。

当您使用 Java 9 或更新版本时,解决问题的最简单方法是

Pattern p = Pattern.compile("(?<=<abc~a>).*?(?=<abc~b>)");
String result = p.matcher(input)
    .replaceAll(m -> m.group().replaceAll("\bsrc\b", "abc"));

基本上,它在幕后与 相同。细微差别是它将使用 StringBuilder 而不是 StringBuffer,该选项仅在 Java 9 之后可用,如果外部模式不匹配,它将 return 原始字符串实例(p) 已找到(而不是副本)。

我还改变了模式使用look-behind和look-ahead,这简化了替换功能,也减少了字符复制量。

请注意,两个 replaceAll 操作具有相似的 appendReplacement loop behind the scenes. The method appendReplacement will search for replacement patterns (e.g. $number) in the replacement string, which does not only apply to "abc" but also the entire group between the <abc~a> and <abc~b> tag. If you can’t preclude the presence of conflicting special characters, you have to use Matcher.quoteReplacement 以避免出现问题。


除了不需要的替换模式解释外,内部 replaceAll 会在每次调用时将模式字符串 compile 转换为 Pattern 对象。此外,内部操作创建了一个临时字符串,然后用于外部替换操作,因此这个简单的解决方案将多次复制一些字符内容。

如果性能真的很重要,那么写一个专门的操作是值得的,即使它更冗长。

static final Pattern OUTER_PATTERN = Pattern.compile("<abc~a>(.*?)<abc~b>");
static final Pattern INNER_PATTERN = Pattern.compile("\bsrc\b");
String replacement = "abc";
String result;
Matcher m = OUTER_PATTERN.matcher(input);
if(!m.find()) result = input;
else {
    StringBuilder sb = new StringBuilder(input.length());
    int copyStart = 0, nextSearchStart;
    do {
        nextSearchStart = m.end();
        for(m.region(m.start(1), m.end(1)).usePattern(INNER_PATTERN);
                                           m.find(); copyStart = m.end()) {
            sb.append(input, copyStart, m.start()).append(replacement);
        }
    } while(m.region(nextSearchStart, input.length()).usePattern(OUTER_PATTERN).find());
    result = copyStart==0? input: sb.append(input, copyStart, input.length()).toString();
}

这不会多次编译模式,而是在没有中间步骤的单个替换操作中使用两种模式,执行必要的最少字符复制。替换字符串使用 StringBuilder.append 按字面复制,因此不需要引号。与内置 replaceAll 一样,当未找到外部模式的匹配项时,它将 return 原始字符串。但当外部模式匹配但受影响区域内没有内部模式匹配时,它也会 return 原始字符串。