2016-12-31 2 views
1

複数のString#replaceAll呼び出しを、Pattern/Matcherインスタンスで置き換える方法を工夫しています。これは、文字列内のテキストを置き換える現在の方法よりも高速であることを期待しています。しかし、私はそれについてどうやって行くのか分からない。ここでJava Regex String#replaceAll Alternative

は、私が操作したい文字列の例です。

@[email protected] is a @[email protected] @[email protected] text. 

あなたが見ることができるように、その間の3つの文字で複数の@文字があります。これは常にそうです。 '@ xxx @'(xxxは小文字でも0から9までの数字でもかまいません)のすべてのインスタンスを置き換えたい場合は、それを実行する最も効率的な方法は何でしょうか?現在、私はそのキーが '@ xxx @'部分文字列であるMapを保存しています。値はその特定の部分文字列を置き換えるものです。 String全体に '@ xxx @'部分文字列が含まれているかどうかを確認し、各インスタンスに対してreplaceAllメソッドを呼び出しますが、これはかなり非効率的です。

ありがとうございました!文字列の部分文字列を異なる文字列で置き換えるパターン/マッチャーは、文字列に部分文字列が含まれているかどうかをチェックし、Stringを使用するより効率的です#replaceAll?もしそうなら、私はどうすればそれについて行きますか?

+0

「でReplaceAll」既に正規表現です。正規表現を使用する方法を学ぶ。 –

+0

@BoristheSpider質問は正規表現を書く方法ではなく、複数の 'replaceAll()'呼び出しを使わずに複数の異なる '@ keyword @'パターンを 'keyword'に依存する値に置き換える方法です。トリックは、['appendReplacement()'](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#appendReplacement-java.lang.StringBuffer-java)です。 lang.String-)と['appendTail()'](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#appendTail-java.lang.StringBuffer- )メソッドを使用します。 – Andreas

+0

@ Andreasありがとうございます。これは、文字列を一度しか検索する必要がない非常に興味深い方法です。 StringBuilderではなくStringBufferを使用した理由はありますか?また、置換可能な〜50の異なる部分文字列があれば、少し冗長になりませんか? –

答えて

1

これはappendReplacementのための比較的簡単なケースである:

// Prepare map of replacements 
Map<String,String> replacement = new HashMap<>(); 
replacement.put("bla", "hello,"); 
replacement.put("red", "world!"); 
// Use a pattern that matches three [email protected] between two @s 
Pattern p = Pattern.compile("@([^@]{3})@"); 
Matcher m = p.matcher("@[email protected] is a @[email protected] @[email protected] text"); 
StringBuffer sb = new StringBuffer(); 
while (m.find()) { 
    // Group 1 captures what's between the @s 
    String tag = m.group(1); 
    String repString = replacement.get(tag); 
    if (repString == null) { 
     System.err.println("Tag @"+tag+"@ is unexpected."); 
     continue; 
    } 
    // Replacement could have special characters, e.g. '\' 
    // Matcher.quoteReplacement() will deal with them correctly: 
    m.appendReplacement(sb, Matcher.quoteReplacement(repString)); 
} 
m.appendTail(sb); 
String result = sb.toString(); 

Demo.

+0

私の文字列は@文字の間に3文字しかないので、これはまさに私が探していたものです。ありがとう! –

3

これは、他の同様の質問へprevious answerのよりダイナミックなバージョンです。

あなたが望む@[email protected]を検索するためのヘルパーメソッドです。 3文字の長さである必要はありません。

private static String replace(String input, Map<String, String> replacement) { 
    StringJoiner regex = new StringJoiner("|", "@(", ")@"); 
    for (String keyword : replacement.keySet()) 
     regex.add(Pattern.quote(keyword)); 
    StringBuffer output = new StringBuffer(); 
    Matcher m = Pattern.compile(regex.toString()).matcher(input); 
    while (m.find()) 
     m.appendReplacement(output, Matcher.quoteReplacement(replacement.get(m.group(1)))); 
    return m.appendTail(output).toString(); 
} 

テスト

Map<String,String> replacement = new HashMap<>(); 
replacement.put("bla", "hello,"); 
replacement.put("red", "world!"); 
replacement.put("Hold", "wait"); 
replacement.put("Better", "more"); 
replacement.put("a?b*c", "special regex characters"); 
replacement.put("foo @ bar", "with spaces and the @ boundary character work"); 

System.out.println(replace("@[email protected] is a @[email protected] @[email protected] text", replacement)); 
System.out.println(replace("But @[email protected], this can do @[email protected]!", replacement)); 
System.out.println(replace("It can even handle @a?b*[email protected] without dying", replacement)); 
System.out.println(replace("Keyword @foo @ [email protected] too", replacement)); 

出力

hello,This is a world!line hello,of text 
But wait, this can do more! 
It can even handle special regex characters without dying 
Keyword with spaces and the @ boundary character work too 
+0

私は本当にあなたの答えが両方とも十分であれば両方の回答を受け入れることができればいいと思っていますが、部分文字列は@記号の間に3文字しかないでしょう。しかし、これは間違いなく将来誰かを助けてくれると思います、ありがとうございます! –

+1

これは、特に見逃しやすい 'Pattern.quote(keyword)'の使用がいいですね。 – dasblinkenlight

+1

@dasblinkenlight DOH!私は 'Matcher.quoteReplacement()'を見逃すことをもっと忘れてしまった。一定。 ;-) – Andreas