40

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

なぜ私はこれを手に入れたのですか?そして、正しい修正は何ですか?前もって感謝します!

4

5 に答える 5

55

${fizz}

{{2,4}は、 「前のトークンの 2 ~ 4 回」を意味するような、繰り返しインジケーターを開始しようとしている正規表現エンジンへのインジケーターです。しかし{f、その後に数字が続く必要があるため、例外がスローされるため、違法です。

$すべての正規表現メタ文字 (この場合は{と)をエスケープする必要があります( http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html#quote(java.lang}を使用してみてください) .String) ) または、文字列の正規表現ではなく、文字列を文字列に置き換える別の方法を使用します。

于 2013-07-04T05:01:36.763 に答える
6

パタシュが指摘したように、問題は にあり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;
}
于 2013-07-04T05:33:10.870 に答える
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();
}
于 2013-07-04T05:10:01.407 に答える
2

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

String regex = "\\$[\\{]([^}]*)[\\}]";
于 2017-10-30T15:33:11.360 に答える
0

String-replaceAll を使用します。「SESSIONKEY1」をテストするためのサンプル入力文字列:

「${SOMESTRING.properties.SESSIONKEY1}」

    String pattern = "\\\"\\$\\{SOMESTRING\\.[^\\}]+\\}\\\""; 
    System.out.println(pattern);
    String result = inputString.replaceAll(pattern, "null");
    return result.toString();
于 2017-04-04T03:54:58.633 に答える