有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

正则表达式Java PatternSyntaxException:字符串替换的非法重复?

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

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

"How now ${fizz} cow. The ${buzz} had oddly-shaped ${foo}."

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

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

那么结果字符串将是:

"How now brown cow. The arsonist had oddly-shaped 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) 个答案

  1. # 1 楼答案

    正如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. # 2 楼答案

    你可以让你的正则表达式有点难看,但是 这会奏效的

    String regex = "\\$[\\{]([^}]*)[\\}]";
    
  3. # 3 楼答案

    改编自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();
    }
    
  4. # 4 楼答案

    ${fizz}

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

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

  5. # 5 楼答案

    使用字符串replaceAll。 用于测试的示例输入字符串 “会话键1”:

    "${SOMESTRING.properties.SESSIONKEY1}"

    ,

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