Java Regex String#replaceAll Alternative

后端 未结 2 1150
时光说笑
时光说笑 2020-12-07 03:18

I\'ve been trying to devise a method of replacing multiple String#replaceAll calls with a Pattern/Matcher instance in the hopes that it would be faster than my current metho

2条回答
  •  粉色の甜心
    2020-12-07 03:39

    This is a more dynamic version of previous answer to another similar question.

    Here is a helper method for searching for any @keyword@ you want. They don't have to be 3 characters long.

    private static String replace(String input, Map 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();
    }
    

    The above runs on Java 8+. In Java 9+, this can be done with lambda expression. The following also fixes the potential issue of a short keyword being a substring of a longer one, by sorting the keywords descending by length.

    private static String replace(String input, Map 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))));
    }
    

    Test

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

    Output

    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
    

提交回复
热议问题