2009-09-23 13 views
37

बहुत आसान सवाल है, लेकिन यह जावा/सी ++ व्यक्ति से जावा की जटिलताओं में आ रहा है।स्ट्रिंग प्रतिस्थापित करें सभी() बनाम Matcher replaceAll() (प्रदर्शन अंतर)

मुझे समझ में आता है कि मैं उत्तर पाने के लिए जुनीट और कुछ प्रदर्शन परीक्षणों को आग लगा सकता हूं; लेकिन मैं बस सोच रहा हूं कि यह वहां है या नहीं।

प्रदर्शन के संदर्भ में String.replaceAll() और Matcher.replaceAll() (Regex.Pterntern से बनाए गए एक मचर ऑब्जेक्ट पर) के बीच अंतर ज्ञात हैं?

इसके अलावा, दोनों के बीच उच्च स्तरीय एपीआई 'आश अंतर क्या हैं? (अचल स्थिति, NULLs हैंडलिंग, रिक्त स्ट्रिंग हैंडलिंग, कॉफी आदि बनाने)

उत्तर

62

String.replaceAll के लिए दस्तावेज़ के अनुसार, यह निम्नलिखित विधि बुला के बारे में क्या कहना है:

रूप str.replaceAll(regex, repl) की इस पद्धति का एक मंगलाचरण पैदावार अभिव्यक्ति के रूप में बिल्कुल वैसा ही परिणाम

Pattern.compile(regex).matcher(str).replaceAll(repl) 

इसलिए,पर हमला करने के बीच प्रदर्शन की उम्मीद की जा सकती है, और स्पष्ट रूप से Matcher और Pattern बनाना समान होना चाहिए।

संपादित

के रूप में टिप्पणी में बताया गया है, प्रदर्शन अंतर किया जा रहा न के बराबर String या Matcher से replaceAll लिए एक कॉल के लिए सही हो जाएगा, फिर भी, अगर एक एकाधिक कॉल प्रदर्शन करने की जरूरत है replaceAll पर, किसी को संकलित Pattern पर पकड़ने के लिए फायदेमंद होने की उम्मीद है, इसलिए अपेक्षाकृत महंगा नियमित अभिव्यक्ति पैटर्न संकलन हर बार निष्पादित नहीं किया जाना चाहिए।

+8

से परे जाने का प्राथमिक कारण है, जैसा कि नीचे वर्णित है, पैटर्न संकलन का प्रदर्शन जुर्माना। यदि आप निरंतर रेगेक्स का उपयोग कर रहे हैं, तो इसे संकलित करें और इसे स्थिर स्थिरता में चिपकाएं। – james

+2

अंत में आपकी "इसलिए" टिप्पणी केवल 1 कॉल के लिए लागू होती है, जिस स्थिति में प्रदर्शन मीट्रिक वास्तव में प्रासंगिक नहीं हैं। यदि एक ही regex के साथ सभी को बदलने के लिए दोहराए गए कॉल हैं तो String.replaceAll संकलित पैटर्न को कैशिंग करने से धीमा है। –

+0

अच्छे अंक के लिए धन्यवाद, मैंने अपना जवाब संपादित कर लिया है। – coobird

3

String.replaceAll के कार्यान्वयन तुम सब कुछ आप जानना चाहते हैं बताता है: (। और डॉक्स का कहना है कि एक ही बात)

return Pattern.compile(regex).matcher(this).replaceAll(replacement); 

जबकि मैंने कैशिंग के लिए चेक नहीं किया है, तो मैं निश्चित रूप से पैटर्न को संकलित करने की अपेक्षा करता हूं और इसके लिए एक स्थिर संदर्भ रखने से Pattern.compile को प्रत्येक पैटर्न के साथ कॉल करने से अधिक कुशल होगा। यदि कोई कैश है तो यह एक छोटी दक्षता बचत होगी - अगर ऐसा नहीं होता है तो यह बड़ा हो सकता है।

9

मुख्य अंतर यह है कि यदि आप पर Matcher का उत्पादन करने के लिए उपयोग करते हैं, तो आप हर बार जब आप इसका उपयोग करते हैं तो रेगेक्स को पुनः संयोजित करने से बच सकते हैं। String के माध्यम से जा रहे हैं, आपको इस तरह "कैश" करने की क्षमता नहीं मिलती है।

यदि आपके पास String कक्षा का replaceAll का उपयोग कर हर बार एक अलग रेगेक्स है, तो ठीक है। यदि आप कई तारों के लिए एक ही रेगेक्स लागू कर रहे हैं, तो एक Pattern बनाएं और इसका पुन: उपयोग करें।String.replaceAll() की

+1

जो मैंने पहले ही कहा है उसे दोहराने के लिए अपना उत्तर खींचना लंगड़ा है। – erickson

+0

अगर इसका उद्देश्य किसी कारण से किया गया था, तो मुझे संदेह है कि जब तक आप अपना उत्तर पोस्ट करते समय मैं पहले ही संपादन कर रहा था ... –

+0

दरअसल, इसका उद्देश्य कोबर्ड था। – erickson

20

स्रोत कोड:

public String replaceAll(String regex, String replacement) { 
    return Pattern.compile(regex).matcher(this).replaceAll(replacement); 
} 

यह पहली बार पैटर्न संकलित करने के लिए है - आप इसे छोटी स्ट्रिंग पर एक ही पैटर्न के साथ कई बार चलाने के लिए जा रहे हैं, प्रदर्शन काफी बेहतर है, तो आप पुन: उपयोग किया जाएगा एक संकलित पैटर्न।

6

अपरिवर्तनीयता/धागा सुरक्षा: संकलित पैटर्न अपरिवर्तनीय हैं, Matchers नहीं हैं। (Is Java Regex Thread Safe? देखें)

रिक्त स्ट्रिंग हैंडलिंग: replaceAll रिक्त स्ट्रिंग शान से संभाल चाहिए (यह एक खाली इनपुट स्ट्रिंग पैटर्न से मेल नहीं खाएगी)

कॉफी बनाना, आदि .: पिछले मैंने सुना, न तो स्ट्रिंग है और न ही पैटर्न है और न ही Matcher इसके लिए कोई एपीआई विशेषताएं थीं।

संपादित करें: एनयूएलएल को संभालने के लिए, स्ट्रिंग और पैटर्न के लिए प्रलेखन स्पष्ट रूप से ऐसा नहीं कहता है, लेकिन मुझे संदेह है कि वे स्ट्रिंग की अपेक्षा करते हुए एक NullPointerException फेंक देंगे।

3

अंतर यह है कि String.replaceAll() प्रत्येक बार इसे रेगेक्स संकलित करता है। .NET की स्थिर Regex.Replace() विधि के लिए कोई समकक्ष नहीं है, जो स्वचालित रूप से संकलित रेगेक्स को कैश करता है। आमतौर पर, replaceAll() कुछ ऐसा होता है जो आप केवल एक बार करते हैं, लेकिन यदि आप बार-बार उसी रेगेक्स के साथ कॉल करने जा रहे हैं, खासकर लूप में, आपको पैटर्न ऑब्जेक्ट बनाना चाहिए और मैचर विधि का उपयोग करना चाहिए।

आप Matcher समय से आगे भी बना सकते हैं, और प्रत्येक उपयोग के लिए यह पुनर्लक्षित करने के लिए अपने विधि रीसेट() का उपयोग करें:

Matcher m = Pattern.compile(regex).matcher(""); 
for (String s : targets) 
{ 
    System.out.println(m.reset(s).replaceAll(repl)); 
} 

, Matcher पुन: उपयोग निश्चित रूप से के प्रदर्शन लाभ, के रूप में कहीं नहीं है पैटर्न का पुन: उपयोग करने के रूप में महान।

0

अन्य उत्तरों ओपी के प्रदर्शन भाग को पर्याप्त रूप से कवर करते हैं, लेकिन Matcher::replaceAll और String::replaceAll के बीच एक और अंतर भी आपके Pattern को संकलित करने का एक कारण है। जब आप Pattern स्वयं संकलित करते हैं, तो रेगेक्स लागू करने के तरीके को संशोधित करने के लिए झंडे जैसे विकल्प होते हैं। उदाहरण के लिए:

Pattern myPattern = Pattern.compile(myRegex, Pattern.CASE_INSENSITIVE); 

Matcher सभी झंडे आप निर्धारित करते हैं Matcher::replaceAll फोन लागू होगी।

अन्य झंडे भी आप सेट कर सकते हैं। अधिकतर मैं सिर्फ यह इंगित करना चाहता था कि Pattern और Matcher एपीआई में बहुत सारे विकल्प हैं, और यह सरल String::replaceAll

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