我一直在尝试设计一种用 Pattern/Matcher 实例替换多个 String#replaceAll 调用的方法,希望它比我当前替换字符串中的文本的方法更快,但我不确定如何着手。
这是我要操作的字符串的示例:
@bla@This is a @red@line @bla@of text.
可以看到,有多个@字符,中间有3个字符;情况总是如此。如果我想替换“@xxx@”的每个实例(其中 xxx 可以是任何小写字母或从 0 到 9 的数字),最有效的方法是什么?目前我正在存储一个 Map,其中它的键是 '@xxx@' 子字符串,值是我想要替换该特定子字符串的内容;我检查整个字符串是否包含“@xxx@”子字符串,并为每个实例调用一个 replaceAll 方法,但我想这效率很低。
非常感谢!
TL;DR - 模式/匹配器用不同的字符串替换字符串的子字符串是否比检查字符串是否包含子字符串并使用 String#replaceAll 更有效?如果是这样,我该怎么做?
最佳答案
这是 previous answer 的动态版本另一个类似的问题。
这是一个帮助方法,用于搜索您想要的任何 @keyword@
。它们的长度不必为 3 个字符。
private static String replace(String input, Map<String, String> replacement) {
StringJoiner regex = new StringJoiner("|", "@(", ")@");
for (String keyword : replacement.keySet())
regex.add(Pattern.quote(keyword));
StringBuffer output = new StringBuffer();
Matcher m = Pattern.compile(regex.toString()).matcher(input);
while (m.find())
m.appendReplacement(output, Matcher.quoteReplacement(replacement.get(m.group(1))));
return m.appendTail(output).toString();
}
以上运行在 Java 8+ 上。在 Java 9+ 中,这可以通过 lambda 表达式来完成。以下内容还通过按长度降序对关键字进行排序,解决了短关键字是较长关键字的子串的潜在问题。
private static String replace(String input, Map<String, String> replacement) {
String regex = replacement.keySet().stream()
.sorted(Comparator.comparingInt(String::length).reversed())
.map(Pattern::quote).collect(Collectors.joining("|", "@(", ")@"));
return Pattern.compile(regex).matcher(input)
.replaceAll(m -> Matcher.quoteReplacement(replacement.get(m.group(1))));
}
测试
Map<String,String> replacement = new HashMap<>();
replacement.put("bla", "hello,");
replacement.put("red", "world!");
replacement.put("Hold", "wait");
replacement.put("Better", "more");
replacement.put("a?b*c", "special regex characters");
replacement.put("foo @ bar", "with spaces and the @ boundary character work");
System.out.println(replace("@bla@This is a @red@line @bla@of text", replacement));
System.out.println(replace("But @Hold@, this can do @Better@!", replacement));
System.out.println(replace("It can even handle @a?b*c@ without dying", replacement));
System.out.println(replace("Keyword @foo @ bar@ too", replacement));
输出
hello,This is a world!line hello,of text
But wait, this can do more!
It can even handle special regex characters without dying
Keyword with spaces and the @ boundary character work too
关于Java 正则表达式字符串#replaceAll 替代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41407648/