रेगेक्स मैचों की सरणी बनाएं


160

जावा में, मैं सभी रेगेक्स मैचों को एक सरणी में वापस करने की कोशिश कर रहा हूं लेकिन ऐसा लगता है कि आप केवल यह जांच सकते हैं कि पैटर्न कुछ से मेल खाता है या नहीं (बूलियन)।

मैं किसी स्ट्रिंग में एक रेगेक्स एक्सप्रेशन से मेल खाते हुए सभी स्ट्रिंग की एक सरणी बनाने के लिए एक रेगेक्स मैच का उपयोग कैसे कर सकता हूं?


2
अच्छा प्रश्न। आपको जो जानकारी चाहिए वह Regex और Matcher पर जावा डॉक्स का हिस्सा होना चाहिए। अफसोस की बात है, यह नहीं है।
चेसो

3
एक असली शर्म। यह कार्यक्षमता लगभग हर दूसरी भाषा (जो नियमित अभिव्यक्ति का समर्थन है) में बॉक्स से बाहर मौजूद है।
रे तोल

जवाबों:


278

( 4castle का जवाब नीचे से बेहतर है अगर आप Java> = 9 मान सकते हैं)

आपको एक माचिस बनाने और उस का उपयोग करने की आवश्यकता है ताकि मैच खोजने के लिए।

 import java.util.regex.Matcher;
 import java.util.regex.Pattern;

 ...

 List<String> allMatches = new ArrayList<String>();
 Matcher m = Pattern.compile("your regular expression here")
     .matcher(yourStringHere);
 while (m.find()) {
   allMatches.add(m.group());
 }

इसके बाद, allMatchesमैच होते हैं, और आप allMatches.toArray(new String[0])एक सरणी प्राप्त करने के लिए उपयोग कर सकते हैं यदि आपको वास्तव में एक की आवश्यकता है।


आप वर्तमान समूह स्थिति का एक स्नैपशॉट रिटर्न करने के MatchResultबाद मैचों पर लूप करने के लिए सहायक कार्यों को लिखने के लिए भी उपयोग कर सकते हैं Matcher.toMatchResult()

उदाहरण के लिए, आप ऐसा करने के लिए एक आलसी इटरेटर लिख सकते हैं

for (MatchResult match : allMatches(pattern, input)) {
  // Use match, and maybe break without doing the work to find all possible matches.
}

इस तरह से कुछ करके:

public static Iterable<MatchResult> allMatches(
      final Pattern p, final CharSequence input) {
  return new Iterable<MatchResult>() {
    public Iterator<MatchResult> iterator() {
      return new Iterator<MatchResult>() {
        // Use a matcher internally.
        final Matcher matcher = p.matcher(input);
        // Keep a match around that supports any interleaving of hasNext/next calls.
        MatchResult pending;

        public boolean hasNext() {
          // Lazily fill pending, and avoid calling find() multiple times if the
          // clients call hasNext() repeatedly before sampling via next().
          if (pending == null && matcher.find()) {
            pending = matcher.toMatchResult();
          }
          return pending != null;
        }

        public MatchResult next() {
          // Fill pending if necessary (as when clients call next() without
          // checking hasNext()), throw if not possible.
          if (!hasNext()) { throw new NoSuchElementException(); }
          // Consume pending so next call to hasNext() does a find().
          MatchResult next = pending;
          pending = null;
          return next;
        }

        /** Required to satisfy the interface, but unsupported. */
        public void remove() { throw new UnsupportedOperationException(); }
      };
    }
  };
}

इसके साथ,

for (MatchResult match : allMatches(Pattern.compile("[abc]"), "abracadabra")) {
  System.out.println(match.group() + " at " + match.start());
}

पैदावार

a at 0
b at 1
a at 3
c at 4
a at 5
a at 7
b at 8
a at 10

4
मैं यहाँ एक ArrayList का उपयोग करने का सुझाव नहीं दूंगा क्योंकि आप आकार को नहीं जानते हैं और बफर के आकार से बचना चाहते हैं। इसके बजाय, मैं एक लिंक्डलिस्ट पसंद करूंगा - हालांकि यह सिर्फ एक सुझाव है और जो भी आपके उत्तर को कम वैध नहीं बनाता है।
लिव

13
@ लिव, दोनों को बेंचमार्क करने के लिए समय निकालें ArrayListऔर LinkedList, परिणाम आश्चर्यजनक हो सकते हैं।
एंथोनी एक्यूपी

मैं सुनता हूं कि आप क्या कह रहे हैं और मुझे दोनों मामलों में निष्पादन की गति और स्मृति पदचिह्न के बारे में पता है; ArrayList के साथ समस्या यह है कि डिफ़ॉल्ट निर्माता 10 की क्षमता बनाता है - यदि आप उस आकार को जोड़ने के लिए कॉल के साथ पिछले जाते हैं ( ) आपको मेमोरी आवंटन और सरणी कॉपी के साथ सहन करना होगा - और यह कुछ समय हो सकता है। दी, यदि आप कुछ मैचों की उम्मीद करते हैं तो आपका दृष्टिकोण अधिक कुशल है; यदि आपको लगता है कि सरणी "आकार बदलना" एक से अधिक बार होता है तो मैं एक लिंक्डलिस्ट का सुझाव दूंगा, और भी अधिक अगर आप कम विलंबता ऐप के साथ काम कर रहे हैं।
Liv

12
@ लिव, यदि आपका पैटर्न काफी प्रेडिक्टेबल साइज़ के साथ मैच का उत्पादन करता है, और यह निर्भर करता है कि पैटर्न स्परली या सघनता से मेल खाता है ( allMatchesबनाम लंबाई के योग के आधार पर yourStringHere.length()), तो आप शायद इसके लिए एक अच्छे साइज़ को बढ़ा सकते हैं allMatches। मेरे अनुभव में, LinkedListस्मृति और पुनरावृत्ति दक्षता-वार की लागत आमतौर पर इसके लायक नहीं है इसलिए यह LinkedListमेरी डिफ़ॉल्ट मुद्रा नहीं है। लेकिन जब एक हॉट-स्पॉट का अनुकूलन किया जाता है, तो निश्चित रूप से सूची कार्यान्वयन को देखने के लिए स्वैप करने के लायक है, अगर आपको सुधार मिलता है।
माइक सैमुअल

1
जावा 9 में, आप अब उपयोग कर सकते हैं Matcher#resultsपाने के लिए एक Streamहै जो आप एक सरणी उत्पन्न करने के लिए उपयोग कर सकते हैं (देखें मेरा उत्तर )।
4castle

56

जावा 9 में, आप अब उपयोग कर सकते हैं Matcher#results()एक पाने के लिए Stream<MatchResult>जो आप के मिलान की सूची / सरणी प्राप्त करने के लिए उपयोग कर सकते हैं।

import java.util.regex.Pattern;
import java.util.regex.MatchResult;
String[] matches = Pattern.compile("your regex here")
                          .matcher("string to search from here")
                          .results()
                          .map(MatchResult::group)
                          .toArray(String[]::new);
                    // or .collect(Collectors.toList())

1
उनका कोई परिणाम नहीं है () विधि, कृपया इसे पहले चलाएं
ब्रावो

14
@ ब्रावो क्या आप जावा 9 का उपयोग कर रहे हैं? यह मौजूद है। मैं प्रलेखन से जुड़ा।
4castle

: (जावा 8 के लिए कोई विकल्प है
लॉगबेसैस

25

जावा रेगेक्स को बहुत जटिल बनाता है और यह पर्ल-स्टाइल का पालन नहीं करता है। MentaRegex पर एक नज़र डालें कि आप जावा कोड की एक पंक्ति में इसे कैसे पूरा कर सकते हैं:

String[] matches = match("aa11bb22", "/(\\d+)/g" ); // => ["11", "22"]

6
यह अच्छा है। डबल स्लैश अभी भी बदसूरत लग रहा है, लेकिन मुझे लगता है कि वहाँ से कोई बलात्कार नहीं है।
जॉनप्रिस्टिन

mentaregex-0.9.5.jar, 6Kb जिसने मेरा दिन बचाया, ओब्रीगाडो सेरियो!
CONvid19

2
ध्यान! सबसे अच्छा समाधान। इसका इस्तेमाल करें!
व्लाद होलुबिएव

14
क्या MentaRegex साइट नीचे है? जब मैं mentaregex.soliveirajr.com पर जाता हूं तो यह केवल "hi" कहता है
user64141

1
@ user64141 ऐसा दिखता है
अमित गोल्ड

11

यहाँ एक सरल उदाहरण दिया गया है:

Pattern pattern = Pattern.compile(regexPattern);
List<String> list = new ArrayList<String>();
Matcher m = pattern.matcher(input);
while (m.find()) {
    list.add(m.group());
}

(यदि आपके पास अधिक कैप्चरिंग समूह हैं, तो आप उन्हें समूह विधि के तर्क के रूप में उनके सूचकांक द्वारा संदर्भित कर सकते हैं। यदि आपको एक सरणी की आवश्यकता है, तो list.toArray())


pattern.matches (इनपुट) काम नहीं करता है। आप अपने regex पैटर्न (फिर से!) पारित करने के लिए है -> डब्ल्यूटीएफ जावा ?! pattern.matches (स्ट्रिंग regex, स्ट्रिंग इनपुट); क्या आपका मतलब है pattern.matcher (इनपुट)?
एल मैक

@ElMac Pattern.matches()एक स्थिर विधि है, आपको इसे Patternउदाहरण पर नहीं कॉल करना चाहिए । Pattern.matches(regex, input)बस के लिए एक आशुलिपि है Pattern.compile(regex).matcher(input).matches()
21o में dimo414

5

से सरकारी Regex जावा ट्रेल्स :

        Pattern pattern = 
        Pattern.compile(console.readLine("%nEnter your regex: "));

        Matcher matcher = 
        pattern.matcher(console.readLine("Enter input string to search: "));

        boolean found = false;
        while (matcher.find()) {
            console.format("I found the text \"%s\" starting at " +
               "index %d and ending at index %d.%n",
                matcher.group(), matcher.start(), matcher.end());
            found = true;
        }

उपयोग करें findऔर groupअपने सरणी / सूची / जो कुछ भी परिणाम में डालें ।


0
        Set<String> keyList = new HashSet();
        Pattern regex = Pattern.compile("#\\{(.*?)\\}");
        Matcher matcher = regex.matcher("Content goes here");
        while(matcher.find()) {
            keyList.add(matcher.group(1)); 
        }
        return keyList;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.