2009-06-12 6 views
63

मेरे पास यह कोड है, और मैं जानना चाहता हूं, अगर मैं जावा रेगेक्स में केवल समूह (सभी पैटर्न नहीं) को प्रतिस्थापित कर सकता हूं। कोड:क्या मैं जावा रेगेक्स में समूहों को प्रतिस्थापित कर सकता हूं?

//... 
Pattern p = Pattern.compile("(\\d).*(\\d)"); 
    String input = "6 example input 4"; 
    Matcher m = p.matcher(input); 
    if (m.find()) { 

     //Now I want replace group one ((\\d)) with number 
     //and group two (too (\\d)) with 1, but I don't know how. 

    } 
+4

क्या आप अपने प्रश्न को स्पष्ट कर सकते हैं, जैसे कि उस इनपुट के लिए अपेक्षित आउटपुट दे सकता है? –

उत्तर

86

उपयोग $nreplaceFirst(...) में कब्जा subsequences का उल्लेख करने (जहां n एक अंक है)। मुझे लगता है कि आप पहले समूह को शाब्दिक स्ट्रिंग "संख्या" और पहले समूह के मान वाले दूसरे समूह के साथ प्रतिस्थापित करना चाहते हैं।

Pattern p = Pattern.compile("(\\d)(.*)(\\d)"); 
String input = "6 example input 4"; 
Matcher m = p.matcher(input); 
if (m.find()) { 
    // replace first number with "number" and second number with the first 
    String output = m.replaceFirst("number $3$1"); // number 46 
} 

(.*) के बजाय दूसरे समूह के लिए (\D+) पर विचार करें। * एक लालची matcher है, और पहले अंतिम अंक उपभोग करेंगे। इसके बाद मैचर को बैकट्रैक करना होगा जब यह अंतिम (\d) को अंतिम अंक से मिलान करने से पहले मैच करने के लिए कुछ भी नहीं है।

+5

अच्छा होगा अगर आपने एक उदाहरण आउटपुट – winklerrr

+5

पोस्ट किया होगा तो यह पहले मैच पर काम करता है, लेकिन अगर कई समूह हैं तो आप काम नहीं करेंगे और आप थोड़ी देर के साथ उन पर फिर से चल रहे हैं (m.find()) –

+1

मैं ह्यूगो से सहमत हूं , यह समाधान को लागू करने का एक भयानक तरीका है ... पृथ्वी पर क्यों यह स्वीकार्य उत्तर है और एसीडीसीजियोर का जवाब नहीं - जो सही समाधान है: कोड की मात्रा, उच्च संयोजन और कम युग्मन, बहुत कम मौका (यदि नहीं मौका) अवांछित साइड इफेक्ट्स ... * श्वास * ... – Wrap2Win

8

.* चारों ओर जोड़ने कोष्ठक द्वारा एक तीसरा समूह जोड़ कर "number" + m.group(2) + "1" साथ परिणाम को बदल दें। उदा .:

String output = m.replaceFirst("number" + m.group(2) + "1"); 
+4

दरअसल, मैचर संदर्भ की $ 2 शैली का समर्थन करता है, इसलिए m.replaceFirst ("संख्या $ 21") वही काम करेगा। –

+0

वास्तव में, वे * एक ही काम नहीं करते हैं। '" संख्या $ 21 "' काम करता है और '" संख्या "+ m.group (2) +" 1 "' नहीं है। –

+2

ऐसा लगता है कि 'संख्या $ 21' समूह 21 को प्रतिस्थापित करेगा, समूह 2 + स्ट्रिंग "1" नहीं। –

1

आप समूह की स्थिति प्राप्त करने के लिए matcher.start() और matcher.end() विधियों का उपयोग कर सकते हैं। तो इस स्थिति का उपयोग करके आप किसी भी पाठ को आसानी से बदल सकते हैं।

33

आप एक सामान्य प्रतिस्थापन विधि का निर्माण करने के Matcher#start(group) और Matcher#end(group) इस्तेमाल कर सकते हैं:

public static String replaceGroup(String regex, String source, int groupToReplace, String replacement) { 
    return replaceGroup(regex, source, groupToReplace, 1, replacement); 
} 

public static String replaceGroup(String regex, String source, int groupToReplace, int groupOccurrence, String replacement) { 
    Matcher m = Pattern.compile(regex).matcher(source); 
    for (int i = 0; i < groupOccurrence; i++) 
     if (!m.find()) return source; // pattern not met, may also throw an exception here 
    return new StringBuilder(source).replace(m.start(groupToReplace), m.end(groupToReplace), replacement).toString(); 
} 

public static void main(String[] args) { 
    // replace with "%" what was matched by group 1 
    // input: aaa123ccc 
    // output: %123ccc 
    System.out.println(replaceGroup("([a-z]+)([0-9]+)([a-z]+)", "aaa123ccc", 1, "%")); 

    // replace with "!!!" what was matched the 4th time by the group 2 
    // input: a1b2c3d4e5 
    // output: a1b2c3d!!!e5 
    System.out.println(replaceGroup("([a-z])(\\d)", "a1b2c3d4e5", 2, 4, "!!!")); 
} 

चेक online demo here

+0

यह वास्तव में स्वीकार्य उत्तर होना चाहिए यह बिना किसी पूर्ण और" जाने के लिए तैयार "समाधान है साथ में कोड के साथ युग्मन का एक स्तर। हालांकि मैं उनमें से किसी एक के विधि नाम बदलने की सिफारिश करता हूं। पहली नज़र में यह पहली विधि में एक रिकर्सिव कॉल की तरह दिखता है। – Wrap2Win

+0

मिस्ड संपादन का मौका। रिकर्सिव कॉल के बारे में हिस्सा वापस ले लें, कोड का सही ढंग से विश्लेषण नहीं किया। अधिभार अच्छी तरह से काम करते हैं – Wrap2Win

0

यहां एक अलग समाधान है, जो कई मैचों में एक समूह के प्रतिस्थापन की अनुमति देता है। यह निष्पादन आदेश को उलट करने के लिए ढेर का उपयोग करता है, इसलिए स्ट्रिंग ऑपरेशन को सुरक्षित रूप से निष्पादित किया जा सकता है।

private static void demo() { 

    final String sourceString = "hello world!"; 

    final String regex = "(hello) (world)(!)"; 
    final Pattern pattern = Pattern.compile(regex); 

    String result = replaceTextOfMatchGroup(sourceString, pattern, 2, world -> world.toUpperCase()); 
    System.out.println(result); // output: hello WORLD! 
} 

public static String replaceTextOfMatchGroup(String sourceString, Pattern pattern, int groupToReplace, Function<String,String> replaceStrategy) { 
    Stack<Integer> startPositions = new Stack<>(); 
    Stack<Integer> endPositions = new Stack<>(); 
    Matcher matcher = pattern.matcher(sourceString); 

    while (matcher.find()) { 
     startPositions.push(matcher.start(groupToReplace)); 
     endPositions.push(matcher.end(groupToReplace)); 
    } 
    StringBuilder sb = new StringBuilder(sourceString); 
    while (! startPositions.isEmpty()) { 
     int start = startPositions.pop(); 
     int end = endPositions.pop(); 
     if (start >= 0 && end >= 0) { 
      sb.replace(start, end, replaceStrategy.apply(sourceString.substring(start, end))); 
     } 
    } 
    return sb.toString();  
} 
2

क्षमा एक मरे हुए घोड़े को हरा, लेकिन यह एक तरह से-अजीब है कि एक इस ओर इशारा किया बाहर है - "हाँ आप कर सकते हैं, लेकिन यह आप कैसे वास्तविक जीवन में समूहों पर कब्जा करने का उपयोग के विपरीत है"।

"6 example input 4".replaceAll("(?:\\d)(.*)(?:\\d)", "number$11"); 

आप आमतौर पर स्ट्रिंग आप चाहते हैं के कुछ हिस्सों पर समूहों पर कब्जा करने का उपयोग नहीं करते:

आप Regex जिस तरह से यह प्रयोग किया जा करने के लिए है का उपयोग करते हैं, समाधान इस के रूप में सरल है को छोड़ दें, आप उन स्ट्रिंग के हिस्से पर उपयोग करें जिन्हें आप रखना चाहते हैं।

यदि आप वास्तव में उन समूहों को चाहते हैं जिन्हें आप प्रतिस्थापित करना चाहते हैं, तो आप शायद एक प्रकार का टेम्पलेट इंजन (जैसे मूंछ, express.js, स्ट्रिंग टेम्पलेट, ...) चाहते हैं।

+0

गैर-कैप्चरिंग समूह अनावश्यक हैं; '\ d (। *) \ d' पर्याप्त होगा। – shmosel

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

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