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

问题描述 投票:0回答:6

我正在尝试编写一个接受

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!)

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

java regex string exception
6个回答
63
投票

${fizz}

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

您需要转义所有正则表达式元字符(在本例中为

$
{
}
)(尝试使用http://docs.oracle.com/javase/6/docs/api/java/util/ regex/Pattern.html#quote(java.lang.String) )或使用不同的方法,用字符串替换字符串,而不是用正则表达式替换字符串。


7
投票

正如 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
投票

改编自

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();
}

2
投票

你可以让你的正则表达式变得有点难看,但是 这会起作用

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

0
投票

使用字符串替换全部。 用于测试的示例输入字符串 “会话密钥1”:

“${SOMESTRING.properties.SESSIONKEY1}”

,

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

0
投票

如果你不知道输入字符串并且它包含 $ 或 { 那么使用这种方式

public static String replacemyownSubStr(String i, String target, String replacement) {
        StringBuilder result = new StringBuilder();
        int lastIndex = 0;
        int index = i.indexOf(target);
        while (index >= 0) {
            result.append(i.substring(lastIndex, index));
            result.append(replacement);
            lastIndex = index + target.length();
            index = i.indexOf(target, lastIndex);
        }
        result.append(i.substring(lastIndex));
        return result.toString();
    }
© www.soinside.com 2019 - 2024. All rights reserved.