2016-05-15 11 views
11

पर प्रतिस्थापित करता है, मैं एक नए प्रारूपित पेड़ पर नोड्स का अनुवाद करने की कोशिश कर रहा हूं, और मुझे सही जगह बदलने में परेशानी हो रही है।जावा एकाधिक एक ही पास

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

और पेड़:: मैं HashMap है कहो

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

समस्या यहाँ हम है पहले एक प्रतिस्थापित किया गया था जो एक नोड बदल दिया। सही पेड़ दिखना चाहिए:

(6:0.07,(30: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) 

लेकिन मैं अपने जावा कार्यान्वयन में परेशानी आ रही:

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; 

    } 

जबकि प्रतिस्थापन काम पर प्रतीत होता है, मैं इंडेक्सिंग को तारों के विभिन्न आकारों के साथ बिल्कुल सही नहीं कर सकता (जैसा कि उदाहरण में दिखाया गया है)। जावा में ऐसा करने का कोई तरीका है?

उत्तर

8

मिलान करते समय आप अपनी स्ट्रिंग को संशोधित करने के लिए Matcher#appendReplacement का उपयोग कर सकते हैं।

ध्यान रखें कि आपके regex [,(]\d+: को सरल किया जा सकता के रूप में अपने विकल्प शाखाओं केवल प्रथम चरित्र में मतभेद ([,(] मैचों या तो , या ()।

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

यह पता चल, एक ऑफसेट मूल्य का उपयोग करने की जरूरत:

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; 

} 

हालांकि, निष्पक्ष चेतावनी, के बाद से इस कार्यान्वयन StringBuilder उपयोग नहीं करता है, यह बड़े तारों पर धीमी गति से हो सकता है।

इसके अतिरिक्त, ऑफ़सेट मान केवल +/- 1 की लंबाई में भिन्नता के लिए काम करता है, और यदि लंबाई अंतर ज्ञात नहीं है तो संशोधित किया जाना चाहिए।

+0

आप इसे पोस्ट करने के बाद 5 मिनट में समस्या हल हो और सवाल के लिए 5 upvotes और जवाब के लिए 4 upvotes मिला:

यहाँ एक IDEONE demo है? काफी फिश लग रहा है। –

+2

@krzyk और वह क्यों है? कोई जवाब तुरंत बाद एक प्रश्न पोस्ट कर सकता है; यह वास्तव में [प्रोत्साहित] है (http://stackoverflow.com/help/self-answer)। – Maroun

+0

हां, यह संभव है, लेकिन पोस्ट करने के बाद 5 मिनट? कोड के एक नए समूह के साथ? मेरे लिए यह सही नहीं दिखता है, और अपवॉट्स की संख्या उस बुरी भावना में जोड़ती है। –

संबंधित मुद्दे