package be.crydust.tokenreplacer;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author kristof
 */
public class TokenReplacer {

    private final String begintoken;
    private final String endtoken;
    private final Map<String, String> replacetokens;

    private Pattern pattern;

    /**
     *
     * @param begintoken
     * @param endtoken
     * @param replacetokens
     */
    public TokenReplacer(String begintoken, String endtoken, Map<String, String> replacetokens) {
        Strings.requireNonEmpty(begintoken);
        Strings.requireNonEmpty(endtoken);
        Objects.requireNonNull(replacetokens);
        if (replacetokens.isEmpty()) {
            throw new IllegalArgumentException("replacetokens");
        }
        for (String key : replacetokens.keySet()) {
            Strings.requireNonEmpty(key);
        }
        this.begintoken = begintoken;
        this.endtoken = endtoken;
        this.replacetokens = new HashMap<>(replacetokens);
    }

    private Pattern getPattern() {
        if (pattern == null) {
            StringBuilder sb = new StringBuilder();
            sb.append(Pattern.quote(begintoken));
            sb.append("(");
            for (String key : replacetokens.keySet()) {
                sb.append(Pattern.quote(key));
                sb.append("|");
            }
            sb.setLength(sb.length() - 1);
            sb.append(")");
            sb.append(Pattern.quote(endtoken));
            pattern = Pattern.compile(sb.toString());
        }
        return pattern;
    }

    /**
     * replaces all occurrences of "begintoken key endtoken" by "value"
     *
     * @param input
     * @return
     */
    public String replace(String input) {
        Matcher matcher = getPattern().matcher(input);
        StringBuffer stringBuffer = new StringBuffer();
        while (matcher.find()) {
            String replacement = Matcher.quoteReplacement(replacetokens.get(matcher.group(1)));
            matcher.appendReplacement(stringBuffer, replacement);
        }
        matcher.appendTail(stringBuffer);
        return stringBuffer.toString();
    }
}

@@ -1786,16 +1786,22 @@
 replace(
+final 
 String i
@@ -1816,16 +1816,22 @@
         
+final 
 Matcher 
@@ -1877,24 +1877,30 @@
         
+final 
 StringBu
 ffer str
@@ -1895,25 +1895,16 @@
 ngBu
-ff
+ild
 er s
-tringBuffer
+b
  = n
@@ -1918,16 +1918,43 @@
 ngBu
-ff
+ild
 er();%0A
+        int position = 0;%0A
     
@@ -1962,17 +1962,16 @@
    while
- 
 (matcher
@@ -1997,43 +1997,150 @@
     
-String replacement = Matcher.quoteR
+// appendReplacement%0A            sb.append(input, position, matcher.start());%0A            position = matcher.end();%0A            final String r
 epla
@@ -2145,17 +2145,19 @@
 lacement
-(
+ = 
 replacet
@@ -2183,17 +2183,16 @@
 roup(1))
-)
 ;%0A      
@@ -2201,48 +2201,18 @@
     
-matcher.appendReplacement(stringBuffer, 
+sb.append(
 repl
@@ -2239,24 +2239,19 @@
         
-matcher.
+// 
 appendTa
@@ -2256,21 +2256,58 @@
 Tail
-(stringBuffer
+%0A        sb.append(input, position, input.length()
 );%0A 
@@ -2325,19 +2325,9 @@
 rn s
-tringBuffer
+b
 .toS

Use StringBuilder in replace