2012-03-01 6 views
32

मैं शब्दों का एक सेट है कहते हैं - सेब, नारंगी, नाशपाती, केला, कीवीजावा रेगेक्स का उपयोग करके, यह जांचने के लिए कि किसी स्ट्रिंग में किसी भी शब्द में कोई शब्द है या नहीं?

मैं एक वाक्य ऊपर सूचीबद्ध से कोई भी शब्द शामिल करता है, तो जाँच करने के लिए चाहते हैं, और यदि ऐसा है, मैं जो शब्द लगाना चाहते हैं मिलान नहीं हुआ। मैं रेगेक्स में इसे कैसे पूरा कर सकता हूं?

मैं वर्तमान में शब्दों में से प्रत्येक के लिए String.indexOf() को कॉल कर रहा हूं। मुझे लगता है कि यह रेगेक्स मिलान के रूप में उतना कुशल नहीं है?

उत्तर

47

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

यह देखने का सबसे अच्छा तरीका है कि कौन सी विधि अधिक कुशल है इसका परीक्षण करना है।

आप अपने गैर-रेगेक्स कोड को सरल बनाने के लिए String.indexOf() के बजाय String.contains() का उपयोग कर सकते हैं।

अलग शब्द नियमित अभिव्यक्ति इस तरह दिखता है खोजने के लिए:

apple|orange|pear|banana|kiwi 

| में रेगुलर एक्सप्रेशन एक OR के रूप में काम करता है।

मेरे बहुत ही साधारण परीक्षण कोड इस तरह दिखता है:

Contains took 5962ms 
Regular Expression took 63475ms 

जाहिर है समय शब्दों की संख्या पर निर्भर करती है के लिए खोज की है और किया जा रहा: इस प्रकार

public class TestContains { 

    private static String containsWord(Set<String> words,String sentence) { 
    for (String word : words) { 
     if (sentence.contains(word)) { 
     return word; 
     } 
    } 

    return null; 
    } 

    private static String matchesPattern(Pattern p,String sentence) { 
    Matcher m = p.matcher(sentence); 

    if (m.find()) { 
     return m.group(); 
    } 

    return null; 
    } 

    public static void main(String[] args) { 
    Set<String> words = new HashSet<String>(); 
    words.add("apple"); 
    words.add("orange"); 
    words.add("pear"); 
    words.add("banana"); 
    words.add("kiwi"); 

    Pattern p = Pattern.compile("apple|orange|pear|banana|kiwi"); 

    String noMatch = "The quick brown fox jumps over the lazy dog."; 
    String startMatch = "An apple is nice"; 
    String endMatch = "This is a longer sentence with the match for our fruit at the end: kiwi"; 

    long start = System.currentTimeMillis(); 
    int iterations = 10000000; 

    for (int i = 0; i < iterations; i++) { 
     containsWord(words, noMatch); 
     containsWord(words, startMatch); 
     containsWord(words, endMatch); 
    } 

    System.out.println("Contains took " + (System.currentTimeMillis() - start) + "ms"); 
    start = System.currentTimeMillis(); 

    for (int i = 0; i < iterations; i++) { 
     matchesPattern(p,noMatch); 
     matchesPattern(p,startMatch); 
     matchesPattern(p,endMatch); 
    } 

    System.out.println("Regular Expression took " + (System.currentTimeMillis() - start) + "ms"); 
    } 
} 

परिणाम मुझे मिल रहे थे तारों की खोज की जा रही है, लेकिन इस तरह की एक साधारण खोज के लिए नियमित अभिव्यक्तियों की तुलना में ~ 10 गुना तेजी से प्रतीत होता है।

किसी अन्य स्ट्रिंग के अंदर स्ट्रिंग्स को खोजने के लिए नियमित अभिव्यक्तियों का उपयोग करके आप अखरोट को तोड़ने के लिए एक स्लेजहैमर का उपयोग कर रहे हैं, इसलिए मुझे लगता है कि हमें आश्चर्य नहीं होना चाहिए कि यह धीमा है। जब आप जो पैटर्न ढूंढना चाहते हैं, उनके लिए नियमित अभिव्यक्तियां अधिक जटिल हैं।

एक मामले में जहां आप रेगुलर एक्सप्रेशन का उपयोग करना चाहते हो सकता है यदि indexOf() और काम नहीं करेगा क्योंकि आप केवल संपूर्ण शब्दों और न सिर्फ सबस्ट्रिंग, उदा मिलान करना चाहते है आप pear से मेल खाना चाहते हैं लेकिन spears नहीं। नियमित अभिव्यक्ति इस मामले को अच्छी तरह से संभालती है क्योंकि उनके पास word boundaries की अवधारणा है।

\b(apple|orange|pear|banana|kiwi)\b 

\b कहते हैं केवल शुरुआत है या एक शब्द के अंत और कोष्ठक समूह मैच के लिए या भाव एक साथ:

इस मामले में हम करने के लिए हमारे पैटर्न को बदल देंगे।

ध्यान दें, जब अपने कोड में इस पद्धति निर्धारित करते समय आपको एक और बैकस्लैश के साथ बैकस्लैश से बचने के लिए की जरूरत है:

Pattern p = Pattern.compile("\\b(apple|orange|pear|banana|kiwi)\\b"); 
7

मुझे नहीं लगता कि एक regexp प्रदर्शन के मामले में एक बेहतर काम कर जाएगा, लेकिन आप इस प्रकार इसका इस्तेमाल कर सकते हैं:

Pattern p = Pattern.compile("(apple|orange|pear)"); 
Matcher m = p.matcher(inputString); 
while (m.find()) { 
    String matched = m.group(1); 
    // Do something 
} 
+5

क्या आप अभी पढ़ नहीं सकते? मैंने कभी नहीं कहा कि यह कुशल था। –

+1

प्रदर्शन रेगेक्स लंबाई पर निर्भर करता है। यदि यह 1000 से कम वर्ण है, तो उस पर जाएं। यदि यह अब आपको अन्य समाधान की आवश्यकता है। उदाहरण के लिए अलग-अलग शब्दों को अलग करने के लिए पाठ को विभाजित करें और उन्हें "ज्ञात" शब्दों के पूर्वनिर्धारित हैश तालिका/सेट के विरुद्ध जांचें। – AlexR

+2

@ डिपोर्टर उत्तर का उद्देश्य एक सही, चमकदार, विश्व स्तरीय समाधान प्रदान न करने के लिए प्रश्न को हल करने के बारे में एक अच्छा संकेत देना है। इसे आसानी से सुधार किया जा सकता है और पठनीयता के लिए, यदि आपके पास 200 स्ट्रिंग्स हैं (इसके लिए रेगेक्सपी का उपयोग न करने का एक और कारण), तो आप 'स्ट्रिंगबिल्डर' में फॉर-लूप और कॉन्सटेनेट का उपयोग कर सकते हैं। मुझे लगता है कि मेरा जवाब पर्याप्त स्वाद प्रदान करता है। –

2

यहाँ सबसे सरल उपाय मैंने पाया (वाइल्डकार्ड के साथ मिलान) है:

boolean a = str.matches(".*\\b(wordA|wordB|wordC|wordD|wordE)\\b.*"); 
संबंधित मुद्दे

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