2016-05-15 2 views
11

新しい形式のツリーでノードを変換しようとしていますが、置き換えの権利が得られません。私はHashMapを持って言う:Java複数が1回のパスで置換されます

"(1:" : "(30:" 
",1:" : ",30:" 
"(30:" : "(6:" 
",30:" : ",6:" 

ツリー:

(30:0.07,(1:0.06,2:0.76)) 

従来の知恵は、複数のreplaceAllを示唆しているが、これは問題を提起:

replaceAll("(1:", "(30:") >> (30:0.07,(30:0.06,2:0.76)) 
replaceAll("(30:", "(6:") >> (6:0.07,(6:0.06,2:0.76)) 

ここでの問題は、我々は」以前に置き換えられたノードが置き換えられました。

def multiple_replace(taxa, text): 
    regex = re.compile("|".join(map(re.escape, taxa.keys()))) 
    return regex.sub(lambda mo: taxa[mo.group(0)], text) 

しかし、私は私のJava実装に問題を抱えている:今、私はすでにPythonでこれをやった

(6:0.07,(30:0.06,2:0.76)) 

private String convertTree (String treeOld, HashMap<String, String> conv) { 
     Pattern pattern = Pattern.compile("\\(\\d+:|,\\d+:"); 
     Matcher matcher = pattern.matcher(treeOld); 
     StringBuilder sbt = new StringBuilder(treeOld); 
     while (matcher.find()) { 
      String replace = conv.get(matcher.group()); 
      System.out.println(matcher.group() + "||" +replace + " || " + matcher.start() + ":"+matcher.end()); 
      sbt.delete(matcher.start(), matcher.end()); 
      sbt.insert(matcher.start(), replace); 
     } 
     return treeOld; 

    } 

ながら正しいツリーは次のようになります。置換が機能しているように見えますが、例のように異なるサイズの文字列でインデックスを作成することはできません。 Javaでこれを行う方法はありますか?この実装はStringBuilderを使用していないので、公正な警告が、それは大規模な文字列に遅いかもしれ

private String singlePassConvert (String text, HashMap<String, String> conv) { 
     Pattern pattern = Pattern.compile("\\(\\d+:|,\\d+:"); 
     Matcher matcher = pattern.matcher(text); 
     int offset = 0; 
     while (matcher.find()) { 
      String replace = conv.get(matcher.group()); 
      String head = (String) text.subSequence(0, matcher.start() + offset); 
      String tail = (String) text.subSequence(matcher.end() + offset, text.length()); 

      text = head + conv.get(matcher.group()) + tail; 

      if (matcher.group().length() > conv.get(matcher.group()).length()) { 
       offset --; 
      } else if (matcher.group().length() < conv.get(matcher.group()).length()) { 
       offset ++; 
      } 
     } 
     return text; 

} 

:。

答えて

8

Matcher#appendReplacementを使用すると、一致している間に文字列を変更できます。

正規表現は、最初の文字([,(],または(と一致する)のみが異なるため、[,(]\d+:に簡略化することができます。ここで

IDEONE demo次のとおりです。

import java.util.*; 
import java.util.regex.*; 
import java.lang.*; 
import java.io.*; 

class Ideone 
{ 
    public static void main (String[] args) throws java.lang.Exception 
    { 
     String tree = "(30:0.07,(1:0.06,2:0.76))"; 
     HashMap<String, String> h = new HashMap<String, String>(); 
     h.put("(1:" , "(30:"); 
     h.put(",1:" , ",30:"); 
     h.put("(30:" , "(6:"); 
     h.put(",30:" , ",6:"); 
     System.out.println(convertTree(tree, h)); 

    } 
    private static String convertTree(String treeOld, HashMap<String, String> conv) { 
     Pattern pattern = Pattern.compile("[,(]\\d+:"); // Init the regex 
     Matcher m = pattern.matcher(treeOld);   // Init the matcher 
     StringBuffer result = new StringBuffer();  // Declare the string buffer (can be replaced with a string builder) 
     while (m.find()) {        // Iterate through matches 
      if (conv.containsKey(m.group(0))) {   // Check if the key exists 
       m.appendReplacement(result, conv.get(m.group(0))); // If yes, use the HashMap value 
      } 
      else { 
       m.appendReplacement(result, m.group(0)); // Else, just reinsert the match value 
      } 
     } 
     m.appendTail(result);  // Append what remains to the result 
     return result.toString(); 

    } 
} 
+1

私の試みよりもずっときれいで、ありがとう! – Darkstarone

7

は、オフセット値を使用するために必要な、それを考え出しました

さらに、オフセット値は長さの差が+/- 1の場合にのみ作用し、長さの違いがわからない場合は変更する必要があります。

+0

あなたはそれを投稿した後、5分で問題を解決し、質問のための5 upvotesと答えのための4 upvotesを得ましたか。かなり怪しいようです。 –

+2

@krzykそしてそれはなぜですか?誰かが質問を投稿した直後に答えを出すことができます。それは実際には(奨励されている)(http://stackoverflow.com/help/self-answer)。 – Maroun

+0

はい、可能ですが、投稿後5分ですか?コードの新しい束で?私のために、それは正しくないと思われ、アップポントの数がその悪い気持ちに加わるだけです。 –

関連する問題