2016-04-07 7 views
0

の製造このJavaラムダ$(で始まり、Mapから所定値と)で終わる文字列を置換しない。のJavaラムダは、正確な文字列結果

SortedMap<String, String> map = new TreeMap<String, String>(); 
map.put("test", "REPLACE"); 
String update = Arrays.stream("$(test) (test)  (test2)".split("\\(\\$|\\)")) 
.map(token -> map.getOrDefault(token, token)) 
.collect(Collectors.joining("")); 

System.out.println(update); 

これはREPLACE (test (test2

これはを印刷しますほとんど期待どおりに動作しますが、閉じ括弧は(test & (test2から削除されています。私は正規表現を更新する必要はありますかラムダを生成するように変更することができます。

REPLACE (test) (test2)

+0

'split'がセパレータを削除します。 – Savior

+0

を試してみてください。http://stackoverflow.com/a/2206432/1214800 – brandonscript

+0

あなたは最初に '$('しかし、あなたのコードは実際には '($ $。 – Jesper

答えて

1

あなたはストリームでこれを行うことができますマップkeySet

public static String replaceKeywords(
     final String template, 
     final Map<String, String> map 
) { 
    return map.keySet().stream().reduce(template, 
      (acc, key) -> acc.replaceAll("\\$\\(" + key + "\\)", map.get(key))); 
} 

用途に削減:

Map<String, String> map = new TreeMap<String, String>(); 
map.put("test", "FOO"); 
map.put("test2", "BAR"); 

System.out.println(replaceKeywords("$(test) $(test2)  (test2)", map)); 

出力:

FOO BAR  (test2) 
+0

これはコードの正しい説明ですか(https://docs.oracle.com/javase/tutorial/collections/streams/reduction.htmlに基づいています)? テンプレートは次のとおりです。リダクションの初期値とストリームに要素がない場合のデフォルトの結果 アキュムレータ関数は2つのパラメータをとります:acc&key accリビジョンの部分結果nとkeyは処理される次の要素です。 一般にアキュムレータの値にはidentity要素が含まれるため、accにはtemplateの値が含まれます。 –

+0

@ blue-skyあなたはそれを持っています – flakes

1

問題は、あなたが一致しない可能性があり$()と一致していることです。 と一致するのは$(で、$(の後には)が続きます。

解決方法1:一致しているときは、「外出先」$(...)文字列にマッチし、マップからトークンを取得するために、それらの内側にテキストをキャプチャし、置換を実行するために、単純な正規表現を使用することができますMatcher#appendReplacementCallback

の使用:

SortedMap<String, String> map = new TreeMap<String, String>(); 
map.put("test", "REPLACE"); 
String update = "$(test) (test)  (test2)"; 
Matcher m = Pattern.compile("\\$\\(([^)]*)\\)").matcher(update); 
StringBuffer sb = new StringBuffer(); 
while (m.find()) { 
    m.appendReplacement(sb, map.getOrDefault(m.group(1), m.group(1))); 
} 
m.appendTail(sb); 
System.out.println(sb); 

IDEONE demo

解決策2を参照してください:Splitと前後参照

でラムダを使用します

免責事項この方法は、あまりにも長い文字列にのみ有効です。

また、ルックアラウンドを使用することもできます。先読みで、問題はない、それは無限の幅です。後読みでは、我々は(代わりに+または*の限定数量詞を使用して)制約幅後読みに頼ることができます。今すぐ読み

SortedMap<String, String> map = new TreeMap<String, String>(); 
map.put("test", "REPLACE"); 
String update = Arrays.stream("$(test) (test)  (test2)" 
    .split("\\$\\((?=[^)]*\\))|(?<=\\$\\([^(]{0,1000})\\)")) 
    .map(token -> map.getOrDefault(token, token)) 
    .collect(Collectors.joining("")); 

System.out.println(update); // => REPLACE (test)  (test2) 

IDEONE demo

正規表現を参照してください:

  • \$\((?=[^)]*\)) - $(に続いて、)以外の0文字が続き、次に)
  • 以外の文字が続きます10
  • | - 又は
  • (?<=\$\([^(]{0,1000})\)から$(で先行さ(以外0-1000(それが十分でなければならない)文字で先行する)と一致。
関連する問題