2009-11-12 16 views
96

Pattern.compile() विधि का महत्व क्या है?
Matcher ऑब्जेक्ट प्राप्त करने से पहले मुझे रेगेक्स स्ट्रिंग को संकलित करने की आवश्यकता क्यों है?java.util.regex - Pattern.compile() का महत्व?

उदाहरण के लिए:

String regex = "((\\S+)\\s*some\\s*"; 

Pattern pattern = Pattern.compile(regex); // why do I need to compile 
Matcher matcher = pattern.matcher(text); 
+2

खैर, कार्यान्वयन (जेडीके 1.7 में) जैसे महत्व लगभग कोई नहीं है, केवल नए पैटर्न (रेगेक्स, 0) के लिए शॉर्टकट है; उस ने कहा, असली महत्व स्थिर विधि नहीं है, लेकिन एक नए पैटर्न की सृजन और वापसी जिसे बाद के उपयोग के लिए बचाया जा सकता है। हो सकता है कि अन्य कार्यान्वयन हो जहां स्थैतिक विधि एक नया मार्ग लेती है और पैटर्न वस्तुओं को कैश करती है, और यह Pattern.compile() महत्व का वास्तविक मामला होगा! – marcolopes

+0

उत्तर पैटर्न और मिलान करने वाले वर्गों को अलग करने के महत्व को हाइलाइट करते हैं (जो शायद प्रश्न पूछता है), लेकिन कोई भी जवाब नहीं देता है कि हम एक स्थिर संकलन समारोह के बजाय केवल कन्स्ट्रक्टर 'नया पैटर्न (रेगेक्स)' क्यों नहीं उपयोग कर सकते हैं। मार्कोप्स टिप्पणी स्पॉट पर है। –

उत्तर

114

compile() विधि को हमेशा किसी बिंदु पर बुलाया जाता है; पैटर्न ऑब्जेक्ट बनाने का यही एकमात्र तरीका है। तो सवाल वास्तव में है, आप इसे स्पष्ट रूप से क्यों कहते हैं? एक कारण यह है कि आपको Matcher ऑब्जेक्ट के संदर्भ की आवश्यकता है ताकि आप कैप्चरिंग समूहों की सामग्री को पुनर्प्राप्त करने के लिए group(int) जैसे विधियों का उपयोग कर सकें। Matcher ऑब्जेक्ट को पकड़ने का एकमात्र तरीका पैटर्न ऑब्जेक्ट की matcher() विधि के माध्यम से है, और पैटर्न ऑब्जेक्ट को पकड़ने का एकमात्र तरीका compile() विधि के माध्यम से है। फिर find() विधि है, जो matches() के विपरीत, स्ट्रिंग या पैटर्न कक्षाओं में डुप्लीकेट नहीं है।

दूसरा कारण एक ही पैटर्न ऑब्जेक्ट को बार-बार बनाने से बचने के लिए है। हर बार जब आप स्ट्रिंग में रेगेक्स-संचालित विधियों में से एक का उपयोग करते हैं (या पैटर्न में स्थिर matches() विधि), यह एक नया पैटर्न और एक नया Matcher बनाता है। तो इस कोड स्निपेट: जाहिर है

for (String s : myStringList) { 
    if (Pattern.compile("\\d+").matcher(s).matches()) { 
     doSomething(); 
    } 
} 

, कि अनावश्यक बहुत काम कर रहा है:

for (String s : myStringList) { 
    if (s.matches("\\d+")) { 
     doSomething(); 
    } 
} 

... वास्तव में इस के बराबर है। वास्तव में, यह वास्तविक मिलान करने के लिए, रेगेक्स को संकलित करने और पैटर्न ऑब्जेक्ट को तुरंत चालू करने में अधिक समय ले सकता है। तो आमतौर पर लूप के उस चरण को खींचने के लिए यह समझ में आता है। आप, साथ ही समय से आगे Matcher बना सकते हैं, हालांकि वे लगभग इतना महंगा नहीं कर रहे हैं:

Pattern p = Pattern.compile("\\d+"); 
Matcher m = p.matcher(""); 
for (String s : myStringList) { 
    if (m.reset(s).matches()) { 
     doSomething(); 
    } 
} 

यदि आप नेट regexes से परिचित हैं, आप सोच हो सकती है यदि जावा के compile() विधि नेट के से संबंधित है RegexOptions.Compiled संशोधक; जवाब न है। जावा की Pattern.compile() विधि केवल .NET के रेगेक्स कन्स्ट्रक्टर के बराबर है। जब आप Compiled विकल्प निर्दिष्ट करते हैं:

Regex r = new Regex(@"\d+", RegexOptions.Compiled); 

...यह रेगेक्स को सीआईएल बाइट कोड पर सीधे संकलित करता है, जिससे इसे बहुत तेजी से करने की इजाजत मिलती है, लेकिन ऊपर की ओर प्रसंस्करण और स्मृति उपयोग में एक महत्वपूर्ण लागत पर - इसे रेगेक्स के लिए स्टेरॉयड के रूप में सोचें। जावा के बराबर नहीं है; String#matches(String) द्वारा दृश्यों के पीछे बनाए गए पैटर्न के बीच कोई अंतर नहीं है और एक जिसे आप Pattern#compile(String) के साथ स्पष्ट रूप से बनाते हैं।

(संपादित करें:।। मैं मूल रूप से कहा गया है कि सभी .NET Regex वस्तुओं कैश नहीं किया जाता है, जो सही नहीं है .NET 2.0 के बाद से, स्वत: कैशिंग केवल Regex.Matches() की तरह स्थिर तरीकों के साथ होता है, जब न तो आप सीधे एक Regex निर्माता फोन ref)

+0

में गुजरकर, संकलन के दौरान case_insensitive, dot_all, आदि जैसे झंडे निर्दिष्ट कर सकते हैं, फिर भी, यह पैटर्न वर्ग पर ऐसी त्रिभुज विधि के महत्व की व्याख्या नहीं करता है! मैंने हमेशा यह माना कि स्थिर विधि Pattern.compile नए पैटर्न (रेगेक्स, 0) के लिए एक साधारण शॉर्टकट से कहीं अधिक थी; मैं संकलित पैटर्न के एक कैच की उम्मीद कर रहा था ... मैं गलत था। हो सकता है कि कैश बनाना नए पैटर्न बनाने से ज्यादा महंगा हो ?? – marcolopes

+7

कृपया ध्यान दें कि Matcher क्लास थ्रेड सुरक्षित नहीं है और इसे थ्रेड में साझा नहीं किया जाना चाहिए। दूसरी तरफ Pattern.compile() है। – gswierczynski

+0

टीएलडीआर; "... [Pattern.compile (...)] सीईएल बाइट कोड पर रेगेक्स को सीधे संकलित करता है, जिससे इसे बहुत तेज प्रदर्शन करने की अनुमति मिलती है, लेकिन ऊपर की ओर प्रसंस्करण और स्मृति उपयोग में एक महत्वपूर्ण लागत पर" –

12

जब आप संकलन Pattern जावा String रों तेजी में खोजने मैचों बनाने के लिए कुछ गणना करता है। (Regex का इन-स्मृति प्रतिनिधित्व बनाता है)

आप Pattern कई बार पुन: उपयोग करने के लिए आप एक नया Pattern हर बार बनाने के ऊपर एक विशाल प्रदर्शन वृद्धि देखना होगा जा रहे हैं।

केवल पैटर्न का उपयोग करने के मामले में, संकलन चरण केवल कोड की एक अतिरिक्त पंक्ति की तरह लगता है, लेकिन वास्तव में, यह सामान्य मामले में बहुत उपयोगी हो सकता है।

+2

बेशक आप इसे एक पंक्ति में लिख सकते हैं 'Matcher matched = Pattern.compile (regex) .matcher (टेक्स्ट); '। एक विधि को शुरू करने के लिए इसके फायदे हैं: तर्क प्रभावी ढंग से नामित होते हैं और यह स्पष्ट है कि बेहतर प्रदर्शन के लिए 'पैटर्न' को कैसे कारक करना है (या विधियों में विभाजित होना)। –

+0

यह हमेशा ऐसा लगता है जैसे आप जावा के बारे में बहुत कुछ जानते हैं। उन्हें आपको उनके लिए काम करने के लिए किराए पर लेना चाहिए ... – jjnguy

+0

@jinguy टॉम की प्रोफाइल देखें – Amarghosh

29

संकलन पार्स नियमित अभिव्यक्ति और मेमोरी प्रतिनिधित्व में बनाता है। संकलन के लिए ओवरहेड एक मैच की तुलना में महत्वपूर्ण है। यदि आप पैटर्न बार-बार का उपयोग कर रहे हैं तो यह संकलित पैटर्न को कैश करने के लिए कुछ प्रदर्शन प्राप्त करेगा।

+4

प्लस आप एक अतिरिक्त झंडे पैरामीटर –

0

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

2

यह प्रदर्शन और स्मृति उपयोग का मामला है, संकलित करें और यदि आप इसे बहुत उपयोग करने की आवश्यकता है तो अनुपालन पैटर्न रखें। रेगेक्स का एक सामान्य उपयोग मान्य उपयोगकर्ता इनपुट (प्रारूप), और उपयोगकर्ताओं के लिए प्रारूप आउटपुट डेटा, इन कक्षाओं में, अनुपालन पैटर्न को सहेजने के लिए, काफी तार्किक लगता है क्योंकि उन्हें आमतौर पर बहुत कुछ कहा जाता है।

नीचे एक नमूना सत्यापनकर्ता, जो वास्तव में, एक बहुत :)

public class AmountValidator { 
    //Accept 123 - 123,456 - 123,345.34 
    private static final String AMOUNT_REGEX="\\d{1,3}(,\\d{3})*(\\.\\d{1,4})?|\\.\\d{1,4}"; 
    //Compile and save the pattern 
    private static final Pattern AMOUNT_PATTERN = Pattern.compile(AMOUNT_REGEX); 


    public boolean validate(String amount){ 

     if (!AMOUNT_PATTERN.matcher(amount).matches()) { 
      return false; 
     }  
     return true; 
    }  
} 

कहा जाता है @Alan मूर ने उल्लेख किया है कि अगर आप अपने कोड में पुन: प्रयोज्य regex है, (उदाहरण के लिए एक पाश से पहले) है, तो आप पुन: उपयोग के लिए पैटर्न संकलित और सहेजना चाहिए।

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