Java PatternSyntaxException:字符串替换非法重复?

时间:2013-07-04 04:57:30

标签: java regex string exception

我正在尝试编写一个接受String的方法,检查某些令牌的实例(例如${fizz}${buzz}${foo}等。)并使用从Map<String,String>

获取的新字符串替换每个标记

例如,如果我将此方法传递给以下字符串:

  

“现在如何$ {fizz} cow。$ {buzz}奇形怪状的$ {foo}。”

如果该方法参考了以下Map<String,String>

Key             Value
==========================
"fizz"          "brown"
"buzz"          "arsonist"
"foo"           "feet"

然后结果字符串将是:

  

“现在的棕色牛怎么样。纵火犯的脚形状奇怪。”

这是我的方法:

String substituteAllTokens(Map<String,String> tokensMap, String toInspect) {
    String regex = "\\$\\{([^}]*)\\}";
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(toInspect);
    while(matcher.find()) {
        String token = matcher.group();     // Ex: ${fizz}
        String tokenKey = matcher.group(1); // Ex: fizz
        String replacementValue = null;

        if(tokensMap.containsKey(tokenKey))
            replacementValue = tokensMap.get(tokenKey);
        else
            throw new RuntimeException("String contained an unsupported token.");

        toInspect = toInspect.replaceFirst(token, replacementValue);
    }

    return toInspect;
}

当我运行它时,我得到以下异常:

Exception in thread "main" java.util.regex.PatternSyntaxException: Illegal repetition near index 0
${fizz}
^
    at java.util.regex.Pattern.error(Pattern.java:1730)
    at java.util.regex.Pattern.closure(Pattern.java:2792)
    at java.util.regex.Pattern.sequence(Pattern.java:1906)
    at java.util.regex.Pattern.expr(Pattern.java:1769)
    at java.util.regex.Pattern.compile(Pattern.java:1477)
    at java.util.regex.Pattern.<init>(Pattern.java:1150)
    at java.util.regex.Pattern.compile(Pattern.java:840)
    at java.lang.String.replaceFirst(String.java:2158)
    ...rest of stack trace omitted for brevity (but available upon request!)

为什么我会这样?什么是正确的解决方案?提前致谢!

5 个答案:

答案 0 :(得分:35)

${fizz}

{是正则表达式引擎的一个指示符,表示您即将启动重复指示符,如{2,4},表示“前一个令牌的2到4倍”。但是{f是非法的,因为它必须跟一个数字,所以它会引发异常。

您需要转义所有正则表达式元字符(在本例中为${})(尝试使用http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html#quote(java.lang.String))或使用替换字符串的其他方法对于字符串,而不是字符串的正则表达式。

答案 1 :(得分:5)

正如Patashu所指出的那样,问题出现在replaceFirst(token, replacementValue)中,它期望第一个参数中的正则表达式,而不是文字。将其更改为replaceFirst(Pattern.quote(token), replacementValue),您就可以了。

我还改变了第一个正则表达式,因为+而不是*的速度更快,但这不是必需的。

static String substituteAllTokens(Map<String,String> tokensMap, String toInspect) {
    String regex = "\\$\\{([^}]+)\\}";
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(toInspect);
    String result = toInspect;
    while(matcher.find()) {
        String token = matcher.group();     // Ex: ${fizz}
        String tokenKey = matcher.group(1); // Ex: fizz
        String replacementValue = null;

        if(tokensMap.containsKey(tokenKey))
            replacementValue = tokensMap.get(tokenKey);
        else
            throw new RuntimeException("String contained an unsupported token.");

        result = result.replaceFirst(Pattern.quote(token), replacementValue);
    }

    return result;
}

答案 2 :(得分:1)

改编自Matcher.replaceAll

boolean result = matcher.find();
if (result) {
    StringBuffer sb = new StringBuffer();
    do {
        String tokenKey = matcher.group(1); // Ex: fizz
        String replacement = Matcher.quoteReplacement(tokensMap.get(tokenKey));
        matcher.appendReplacement(sb, replacement);
        result = matcher.find();
    } while (result);
    matcher.appendTail(sb);
    return sb.toString();
}

答案 3 :(得分:1)

You can make your RegEx a bit ugly, but this will work

String regex = "\\$[\\{]([^}]*)[\\}]";

答案 4 :(得分:0)

使用String-replaceAll。 示例输入字符串用于测试 “SESSIONKEY1”:

  

“$ {SOMESTRING.properties.SESSIONKEY1}”

    String pattern = "\\\"\\$\\{SOMESTRING\\.[^\\}]+\\}\\\""; 
    System.out.println(pattern);
    String result = inputString.replaceAll(pattern, "null");
    return result.toString();