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

2022-09-01 02:33:06

我正在尝试编写一个方法,该方法将接受一个,检查它是否存在某些标记(例如,,,等)的实例,并将每个令牌替换为从中获取的新字符串。String${fizz}${buzz}${foo}Map<String,String>

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

“现在怎么样${fizz} 牛。${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!)

为什么我会得到这个?正确的解决方法是什么?提前致谢!


答案 1

${fizz}

{是正则表达式引擎的指标,表示您将要启动重复指标,这意味着“上一个令牌的 2 到 4 倍”。但这是非法的,因为它后面必须跟着一个数字,所以它会引发一个异常。{2,4}{f

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


答案 2

正如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;
}