Java Regex String#replaceAll Alternative

时间:2016-12-31 10:50:39

标签: java regex string pattern-matching substring

我一直在尝试设计一个用Pattern / Matcher实例替换多个String#replaceAll调用的方法,希望它比我当前替换字符串中的文本的方法更快,但我不确定如何去做。

以下是我想要操作的String的示例:

@bla@This is a @red@line @bla@of text.

如您所见,有多个@字符,中间有3个字符;情况总是如此。如果我想替换'@ xxx @'的每个实例(其中xxx可以是从0到9的任何小写字母或数字),那么最有效的方法是什么呢?目前我正在存储一个Map,其键是'@ xxx @'子串,并且值是我想要替换特定子串的值;我检查整个String是否包含'@ xxx @'子串,并为每个实例调用replaceAll方法,但我认为这是非常低效的。

非常感谢!

TL; DR - 使用不同的String替换String的子串的Pattern / Matcher是否比检查String是否包含子串并使用String#replaceAll更有效?如果是这样,我该怎么做呢?

2 个答案:

答案 0 :(得分:3)

对于另一个类似的问题,这是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();
}

测试

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

答案 1 :(得分:2)

对于appendReplacement来说,这是一个相对简单的案例:

// Prepare map of replacements
Map<String,String> replacement = new HashMap<>();
replacement.put("bla", "hello,");
replacement.put("red", "world!");
// Use a pattern that matches three non-@s between two @s
Pattern p = Pattern.compile("@([^@]{3})@");
Matcher m = p.matcher("@bla@This is a @red@line @bla@of text");
StringBuffer sb = new StringBuffer();
while (m.find()) {
    // Group 1 captures what's between the @s
    String tag = m.group(1);
    String repString = replacement.get(tag);
    if (repString == null) {
        System.err.println("Tag @"+tag+"@ is unexpected.");
        continue;
    }
    // Replacement could have special characters, e.g. '\'
    // Matcher.quoteReplacement() will deal with them correctly:
    m.appendReplacement(sb, Matcher.quoteReplacement(repString));
}
m.appendTail(sb);
String result = sb.toString();

Demo.