2011-10-05 13 views
8

कहें कि मेरे पास एक फ़ाइल है, जिसमें कुछ टेक्स्ट है। इसमें "substr1", "substr2", "substr3" इत्यादि जैसी सबस्ट्रिंग्स हैं। मुझे उन सभी सबस्ट्रिंग्स को किसी अन्य टेक्स्ट, जैसे "repl1", "repl2", "repl3" के साथ प्रतिस्थापित करने की आवश्यकता है। अजगर में, मैं इस तरह एक शब्दकोश बनाने होगा:एक बार में कई सबस्ट्रिंग्स को बदलें

{ 
"substr1": "repl1", 
"substr2": "repl2", 
"substr3": "repl3" 
} 

और पैटर्न के साथ कुंजी में शामिल होने का सृजन '|', तो re.sub समारोह के साथ बदलें। क्या जावा में ऐसा करने का कोई आसान तरीका है?

+0

संबंधित धागा - http://stackoverflow.com/questions/2049528/java-best-way-for-string-find-and-replace – adatapost

उत्तर

14

इस प्रकार से आपका अजगर-सुझाव जावा के लिए अनुवाद है:

Map<String, String> replacements = new HashMap<String, String>() {{ 
    put("substr1", "repl1"); 
    put("substr2", "repl2"); 
    put("substr3", "repl3"); 
}}; 

String input = "lorem substr1 ipsum substr2 dolor substr3 amet"; 

// create the pattern joining the keys with '|' 
String regexp = "substr1|substr2|substr3"; 

StringBuffer sb = new StringBuffer(); 
Pattern p = Pattern.compile(regexp); 
Matcher m = p.matcher(input); 

while (m.find()) 
    m.appendReplacement(sb, replacements.get(m.group())); 
m.appendTail(sb); 


System.out.println(sb.toString()); // lorem repl1 ipsum repl2 dolor repl3 amet 

यह दृष्टिकोण एक समानांतर (अर्थात "एक ही बार में") प्रतिस्थापन है। अर्थात, यदि आप

"a" -> "b" 
"b" -> "c" 

के लिए हुआ तो इस दृष्टिकोण "a b" -> "b c" के रूप में आप का सुझाव दे जवाब करने का विरोध किया जाना चाहिए replace या replaceAll के लिए श्रृंखला कई कॉल जो "c c" देना होगा देना होगा।


(आप प्रोग्राम के regexp बनाने के लिए इस दृष्टिकोण सामान्य हैं, तो सुनिश्चित करें कि आप Pattern.quote प्रत्येक व्यक्ति के खोज शब्द और Matcher.quoteReplacement प्रत्येक प्रतिस्थापन शब्द।)

+0

यह दृष्टिकोण StringUtils.replaceEach से भिन्न कैसे है? या प्रतिस्थापन के रूप में एक ही जगह है? –

+0

यह दृष्टिकोण अधिक सामान्य है क्योंकि आप एक मनमानी प्रतिस्थापन-फ़ंक्शन प्रदान कर सकते हैं ('m.appendReplacement' लाइन देखें)। दूसरी बात यह है कि आपको स्ट्रिंग-मैनिपुलेशन रूटीन के लिए किसी तृतीय पक्ष लाइब्रेरी को शामिल करने की आवश्यकता नहीं है। (यदि आप पहले से ही अपाचे कॉमन्स पर निर्भर हैं, या किसी अन्य निर्भरता के साथ परेशान नहीं हैं, तो 'replaceEach' दृष्टिकोण के साथ जाएं।) – aioobe

+0

(नहीं,' replaceEach' 'replaceAll' जैसा नहीं है। 'ReplaceAll' 'प्रतिस्थापन' का सिर्फ एक regexp संस्करण है।) – aioobe

2
yourString.replace("substr1", "repl1") 
      .replace("substr2", "repl2") 
      .replace("substr3", "repl3"); 
+4

+1 ... हालांकि यह "सभी एक बार" नहीं है। अगर उदाहरण अलग था, तो एक "->" बी "' और '" बी "->" सी "कहें तो परिणाम में कोई 'बी' नहीं होगा, भले ही' इनपुट में – aioobe

+0

बहुत बदसूरत लग रहा है, लेकिन वैसे भी धन्यवाद :) –

+0

@aioobe: 'StringUtils.replaceEach() 'इस अच्छी तरह से संभालता है। – palacsint

-1
return yourString.replaceAll("substr1","relp1"). 
        replaceAll("substr2","relp2"). 
        replaceAll("substr3","relp3") 
+0

-1। यह सब एक बार में नहीं है, और सादा स्ट्रिंग विधि (प्रतिस्थापन) के बजाय अनावश्यक रूप से एक regex विधि (replaceAll) का उपयोग करता है। – Boann

1

पहले, समस्या का एक प्रदर्शन:

String s = "I have three cats and two dogs."; 
s = s.replace("cats", "dogs") 
    .replace("dogs", "budgies"); 
System.out.println(s); 

यह बिल्लियों => कुत्तों और कुत्तों => budgies को बदलने के लिए इरादा है, लेकिन अनुक्रमिक प्रतिस्थापन पिछले आर के परिणाम पर चल रही है प्रतिस्थापन, इसलिए दुर्भाग्यपूर्ण आउटपुट है:

मेरे पास तीन budgies और दो budgies है।

यहां एक साथ प्रतिस्थापन विधि का मेरा कार्यान्वयन है। यह String.regionMatches का उपयोग कर लिखने के लिए आसान है:

public static String simultaneousReplace(String subject, String... pairs) { 
    if (pairs.length % 2 != 0) throw new IllegalArgumentException(
     "Strings to find and replace are not paired."); 
    StringBuilder sb = new StringBuilder(); 
    int numPairs = pairs.length/2; 
    outer: 
    for (int i = 0; i < subject.length(); i++) { 
     for (int j = 0; j < numPairs; j++) { 
      String find = pairs[j * 2]; 
      if (subject.regionMatches(i, find, 0, find.length())) { 
       sb.append(pairs[j * 2 + 1]); 
       i += find.length() - 1; 
       continue outer; 
      } 
     } 
     sb.append(subject.charAt(i)); 
    } 
    return sb.toString(); 
} 

परीक्षण:

String s = "I have three cats and two dogs."; 
s = simultaneousReplace(s, 
    "cats", "dogs", 
    "dogs", "budgies"); 
System.out.println(s); 

आउटपुट:

मैं तीन कुत्तों और दो budgies की है।

इसके अतिरिक्त, यह कभी-कभी उपयोगी होता है जब यह एक साथ प्रतिस्थापन करता है, ताकि सबसे लंबा मैच देखने के लिए सुनिश्चित किया जा सके। (PHP के strtr फ़ंक्शन यह उदाहरण के लिए करता है।) यहां इसके लिए मेरा कार्यान्वयन है:

public static String simultaneousReplaceLongest(String subject, String... pairs) { 
    if (pairs.length % 2 != 0) throw new IllegalArgumentException(
     "Strings to find and replace are not paired."); 
    StringBuilder sb = new StringBuilder(); 
    int numPairs = pairs.length/2; 
    for (int i = 0; i < subject.length(); i++) { 
     int longestMatchIndex = -1; 
     int longestMatchLength = -1; 
     for (int j = 0; j < numPairs; j++) { 
      String find = pairs[j * 2]; 
      if (subject.regionMatches(i, find, 0, find.length())) { 
       if (find.length() > longestMatchLength) { 
        longestMatchIndex = j; 
        longestMatchLength = find.length(); 
       } 
      } 
     } 
     if (longestMatchIndex >= 0) { 
      sb.append(pairs[longestMatchIndex * 2 + 1]); 
      i += longestMatchLength - 1; 
     } else { 
      sb.append(subject.charAt(i)); 
     } 
    } 
    return sb.toString(); 
} 

आपको इसकी आवश्यकता क्यों होगी? उदाहरण इस प्रकार है:

String truth = "Java is to JavaScript"; 
truth += " as " + simultaneousReplaceLongest(truth, 
    "Java", "Ham", 
    "JavaScript", "Hamster"); 
System.out.println(truth); 

आउटपुट:

जावा जावास्क्रिप्ट करने के लिए है हम simultaneousReplaceLongest की simultaneousReplace बजाय, उत्पादन पड़ता था "HamScript" का इस्तेमाल किया था, तो के रूप में हाम हैम्स्टर

है "हैम्स्टर" के बजाय :)

ध्यान दें कि उपरोक्त विधियां केस-संवेदी हैं। यदि आपको केस-असंवेदनशील संस्करणों की आवश्यकता है तो उपरोक्त को संशोधित करना आसान है क्योंकि String.regionMatchesignoreCase पैरामीटर ले सकता है।

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