繁体   English   中英

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

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

我在标签中有一个字符串。 例如:“<abc~a>我是 src scr 客户<abc~b>”

我想用“abc”替换“src”。 我使用以下正则表达式替换:- replacAll("(<abc~a>. ?)src(. ?<abc~b>)"),"$1"+"abc"+"$2"); 但它只替换第一次出现的字符串,即 output is "<abc~a>I am abc src customer<abc~b>"

我希望 output 为“<abc~a>我是 abc abc 客户<abc~b>”。

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

我们可以在这里尝试使用正式的正则表达式模式匹配器。 匹配模式<abc~a>(.*?)<abc~a> ,并且对于每个匹配 append 的标签, 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());

这打印:

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

请注意,在许多其他语言中,我们可以使用正则表达式回调 function。 但是核心 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 ) 的匹配项(而不是副本),它将返回原始字符串实例。

我还将模式更改为使用后视和前瞻,这简化了替换 function 并减少了字符复制量。

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


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

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

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一样,当没有找到外部模式的匹配项时,它将返回原始字符串。 但是,当外部模式匹配但受影响区域内没有内部模式匹配时,它也会返回原始字符串。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM