2017-11-08 15 views
0

私はString"abc|a&b")ですが、Stringの部分を他のStringに置き換えたいと思います。置換はHashMap<String, String>に保存され、次のようにされている。ハッシュマップ値を使用して文字列を取得するエラー

  1. "a">"true"
  2. "b">"false"
  3. ​​>"true"

私の結果は"truefalsec|true&false"ですが、私は"true|true&false"

が必要

マイコプターe:

for(Map.Entry<String, String> entry: map.entrySet()) { 
    if(expression.contains(entry.getKey())) 
     expression = expression.replace(entry.getKey(), entry.getValue()); 
} 
System.out.println(expression); 

皆さんお気軽にご意見をお聞かせください。

+2

長さによって減少ソートあなたの鍵は、その順序でそれらを適用します。 – rgettman

+0

あなたは3つの答えを持っていますが、すべてあなたの問題を解決しています。以前あなたが私の答えを受け入れてコメントしたので(あなたのコメントは削除していますが)、あなたはそれらを見たことが分かります。どうして?人々はあなたを助けるために真剣に取り組んでいます –

答えて

1

問題は、先にaまたはbを置き換えることです。その後、abcは残っておらず、交換されません。 LinkedHashMapを使用して、置換する順序で要素を挿入することができます。LinkedHashMapを使用すると、挿入した順序でその値を反復処理できますが、HashMapはキーに依存しますhashCode。 >あなたが必要なものを変更して文字列に戻す全体をマージ -

Map<String, String> map = new LinkedHashMap<>(); 
map.put("abc", "true"); 
map.put("a", "true"); 
map.put("b", "false"); 

for(Map.Entry<String, String> entry: map.entrySet()) { 
    expression = expression.replace(entry.getKey(), entry.getValue()); 
} 
System.out.println(expression); 
1
String expression = "abc|a&b"; 

    Map<String, String> map = new LinkedHashMap<>(); 

    map.put("a", "true"); 
    map.put("abc", "true"); 
    map.put("b", "false"); 

    List<String> parts = Arrays.stream(expression.split("\\W+")).filter(map::containsKey) 
      .map(map::get).collect(Collectors.toList()); 

    Queue<String> separators = new LinkedList<>(Arrays.asList(expression.split("\\w+")) 
      .stream().filter(s -> !s.isEmpty()) 
      .collect(Collectors.toList())); 

    StringBuilder result = new StringBuilder(); 

    for(String part : parts){ 
     result.append(part).append(!separators.isEmpty() ? separators.poll() : ""); 
    } 

    System.out.println(result.toString()); 

あなたはセパレータのため、同じ表現からすべてのキーを取得するためのストリームを使用することができます。

1

問題は、次の置換のためにスキャンを再開し、最初に最短の入力をスキャンすることです。 abcaをスキャンすることで

aが既にabcのためにスキャンする前に、何か他のものに置き換えられているので、あなたは、abcに一致することはありません。最初に長さをスキャンする部分を並べ替えて、commented by rgettmanとします。

入力ごとにスキャンを再開することで、置換値の内容を置き換えることができます。例えば。あなたがabをスキャンすれば、bfalseによって置き換えられますが、その後falseabその結果、trueによって置き換えられますftruelseに置き換え始めます。

第2の問題を解決し、パフォーマンスを向上させるには、入力を1回スキャンするだけです。

一度入力をスキャンする最も簡単な方法は、複数のテキストのいずれかの走査は、即ち、第1 |、最長のキーによって分離されたキーをリスト、abc|a|bような正規表現を使用することです。

置換マッピングが何でもかまいませんと仮定すると、Mapから正規表現を動的に構築する必要があります。キーとマップの値の両方を引用することを覚えておいてください。したがって、特殊文字は正規表現の特殊文字として扱われず、例えば一致する任意の文字.。ここ

正規表現交換ループを使用して、すべてのことを実行する(ジャワ8)方法であって

public static String replace(String input, Map<String, String> replacementValues) { 
    String regex = replacementValues.keySet().stream() 
        .sorted(Comparator.comparingInt(String::length).reversed() 
            .thenComparing(Function.identity())) 
        .map(Pattern::quote) 
        .collect(Collectors.joining("|")); 
    StringBuffer buf = new StringBuffer(input.length() + 16); 
    Matcher m = Pattern.compile(regex).matcher(input); 
    while (m.find()) 
     m.appendReplacement(buf, Matcher.quoteReplacement(replacementValues.get(m.group()))); 
    return m.appendTail(buf).toString(); 
} 

テスト

Map<String, String> map = new HashMap<>(); 
map.put("a", "true"); 
map.put("b", "false"); 
map.put("abc", "true"); 
System.out.println(replace("abc|a&b", map)); 

出力

true|true&false


スキャンは言葉ではなく、ストリングと一致し、コンパイルする正規表現を変更する必要がある場合:

Pattern.compile("\\b(?:" + regex + ")\\b")