如何替换标签<>在java中使用regex



我在标记中有一个字符串。例如:"<abc~a>我是src scr客户<abc~b>quot;

我想替换";src";用";abc";。我使用以下正则表达式替换:-replacAll("(<abc~a>.?(src(.?<abc~b>("("1〃+"abc"+"2〃(;但它只替换字符串的第一次出现,即输出为"0"<abc~a>我是abc src客户<abc~b>quot;

我希望输出为"<abc~a>我是abc abc客户<abc~b>";。

我不想用火柴图案。有没有使用replaceAll((的解决方案?请帮忙。

我们可以尝试在这里使用正式的regex模式匹配器。在模式<abc~a>(.*?)<abc~a>上进行匹配,并且对于每个匹配,附加用abc替换src的标签。这是一个示例代码:

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());

此打印:

这里有一个src<abc~a>我是abc的客户<abc~b>这里还有另一个src。

请注意,在许多其他语言中,我们本可以使用regex回调函数。但是核心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以来才可用的选项,并且如果没有找到与外部模式(p(匹配的内容(而不是副本(,它将返回原始字符串实例。

我还将模式更改为使用向后看和向前看,这简化了替换功能,也减少了字符复制的数量。

请注意,两个replaceAll操作在幕后都具有类似的appendReplacement循环。方法appendReplacement将在替换字符串中搜索替换模式(例如$number(,这不仅适用于"abc",而且适用于<abc~a><abc~b>标签之间的整个组。如果不能排除冲突特殊字符的存在,则必须使用Matcher.quoteReplacement来避免问题。


除了对替换模式进行不必要的解释外,内部replaceAll还会在每次调用时将模式字符串编译为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一样,当没有找到外部模式的匹配时,它将返回原始字符串。但是,当外部模式匹配但受影响区域内没有内部模式匹配时,它也会返回原始字符串。

最新更新