जब आपको रेगुलर एक्सप्रेशन का उपयोग नहीं करना चाहिए? [बन्द है]


50

प्रोग्रामर के शस्त्रागार में नियमित अभिव्यक्तियाँ शक्तिशाली उपकरण हैं, लेकिन - कुछ मामले हैं जब वे सबसे अच्छा विकल्प नहीं हैं, या एकमुश्त हानिकारक भी हैं।

सरल उदाहरण # 1 regexp के साथ HTML पार्स कर रहा है - कई बग के लिए एक ज्ञात सड़क। संभवतः, यह सामान्य रूप से पार्सिंग का भी गुण है ।

लेकिन, क्या नियमित अभिव्यक्तियों के लिए अन्य स्पष्ट रूप से नो-गो क्षेत्र हैं?


ps: " आप जो प्रश्न पूछ रहे हैं वह व्यक्तिपरक प्रतीत होता है और बंद होने की संभावना है। " - इस प्रकार, मैं जोर देना चाहता हूं, कि मैं उन उदाहरणों में दिलचस्पी रखता हूं जहां regexps का उपयोग समस्याओं के कारण जाना जाता है।


9
Regexp के साथ HTML पार्स करना "केवल कई बग के लिए एक ज्ञात सड़क" नहीं है। यह वास्तव में असंभव है
क्रामि ने मोनिका को

19
इतना ही नहीं यह असंभव है, यह पागलपन और अनन्त लानत की
मार्टिन विकमैन

3
@ Jörg: Regexp नियमित अभिव्यक्ति के लिए एक संक्षिप्त नाम है।
जोरेन

3
@ जोर्ग: यह बहुत हद तक सही है कि सॉफ्टवेयर लाइब्रेरी में गणित के नियमित भाव और उनके कार्यान्वयन में भारी अंतर है। यह भी सच है कि अधिकांश नियमित अभिव्यक्ति पुस्तकालयों में एक्सटेंशन होते हैं जो उन्हें केवल नियमित भाषाओं को स्वीकार करने से परे रखते हैं, और उन्हें नियमित रूप से अभिव्यक्त करना हमेशा उचित नहीं होता है। मैं आपसे सहमत हूं कि दो अलग-अलग अवधारणाएं हैं। लेकिन उनका एक ही नाम है; regexp अभी भी केवल एक संक्षिप्त नाम है, अपने आप में एक शब्द नहीं है। सॉफ्टवेयर पुस्तकालयों के लिए पूर्ण शब्द का उपयोग करने की इस साइट पर इस उदाहरण के बहुत सारे।
जोरेन

2
@ जार्ग - ये शब्दार्थ हैं। हालांकि इन पैटर्नों को अलग-अलग नामों से बुलाना एक अच्छा विचार हो सकता है (यदि केवल "नियमित भावों से बचने के लिए" नियमित भाषाओं के लिए "अशुद्धता" हो, "रेगेक्सप" / "नियमित अभिव्यक्ति" बहुत अच्छा प्रयास नहीं है, और केवल इसकी ओर जाता है) अतिरिक्त भ्रम।
कोबी

जवाबों:


60

नियमित अभिव्यक्ति का उपयोग न करें:

  • जब पार्सर होते हैं।

यह HTML तक सीमित नहीं है । एक साधारण वैध XML को एक नियमित अभिव्यक्ति के साथ यथोचित रूप से पार्स नहीं किया जा सकता है, भले ही आप स्कीमा जानते हों और आपको पता हो कि यह कभी नहीं बदलेगा।

उदाहरण के लिए, C # स्रोत कोड को पार्स करने का प्रयास न करें । इसके बजाय, एक सार्थक पेड़ संरचना या टोकन प्राप्त करने के लिए इसे पार्स करें।

  • अधिक आम तौर पर, जब आपके पास अपना काम करने के लिए बेहतर उपकरण होते हैं।

क्या होगा अगर आपको एक पत्र की तलाश करनी चाहिए, छोटी और पूंजी दोनों? यदि आप नियमित अभिव्यक्ति पसंद करते हैं, तो आप उनका उपयोग करेंगे। लेकिन क्या एक के बाद एक दो खोजों का उपयोग करना आसान / तेज़ / पठनीय नहीं है? संभावनाएं अधिकांश भाषाओं में हैं जिनसे आप बेहतर प्रदर्शन प्राप्त करेंगे और अपने कोड को अधिक पठनीय बना पाएंगे।

उदाहरण के लिए इंगो के जवाब में नमूना कोड एक अच्छा उदाहरण है जब आपको नियमित अभिव्यक्ति का उपयोग नहीं करना चाहिए। बस खोजते हैं foo, फिर के लिए bar

  • जब मानव लेखन को पार्स कर रहा है।

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

  • कुछ प्रकार के डेटा को मान्य करते समय।

उदाहरण के लिए, एक ई-मेल पते को एक नियमित अभिव्यक्ति के माध्यम से मान्य नहीं करें। ज्यादातर मामलों में, आप इसे गलत करेंगे। एक दुर्लभ मामले में, आप इसे सही करेंगे और 6 343 अक्षरों की लंबाई वाली कोडिंग हॉरर के साथ समाप्त करेंगे ।

सही उपकरणों के बिना, आप गलतियाँ करेंगे। और आप उन्हें अंतिम क्षण में नोटिस करेंगे, या शायद कभी नहीं। यदि आप साफ कोड की परवाह नहीं करते हैं, तो आप कोई टिप्पणी, कोई रिक्त स्थान, कोई newlines के साथ एक बीस लाइनों स्ट्रिंग लिखेंगे।

  • जब आपका कोड पढ़ लिया जाएगा। और फिर अलग-अलग डेवलपर्स द्वारा हर बार फिर से, और फिर से पढ़ा।

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


9
"गंभीरता से, अगर मैं आपका कोड लेता हूं और इसकी समीक्षा करनी चाहिए या इसे संशोधित करना चाहिए, तो मैं एक सप्ताह बिताने के लिए बीस लाइनों लंबी प्रतीकों के बहुत सारे प्रतीकों को समझने की कोशिश नहीं करना चाहता।" +1!
फंकीब्रुक

1
स्टैक ओवरफ्लो पर अपनी सौतेली बहन की तुलना में यह बहुत बेहतर उत्तर है: stackoverflow.com/questions/7553722/…
कोबी

1
यदि आप पर्ल / पीसीआरई का उपयोग कर रहे हैं (और संभवत: अन्य आधुनिक रेगेक्स फ्लेवर भी), सबरूटीन्स के बारे में पढ़ें, कैप्चरिंग ग्रुप्स एंड (?(DEFINE))एसेरिज़न्स;) का उपयोग करके आप उन लोगों का उपयोग करके बहुत ही साफ रेगीक्स लिख सकते हैं और वास्तव में जब आप उपयोग करते हैं तो आप व्याकरण लिखेंगे। बहुत कुछ वैसा ही जैसा आप yacc या alike में लिखते हैं;)
NikiC

2
ब्लैक लिस्टेड शब्दों को दूर करने के लिए नियमित अभिव्यक्तियों का उपयोग करना एक क्लैबटिक त्रुटि है।
डैन रे

दुनिया में ऐसा कोई कारण नहीं है कि जैसे एक स्ट्रिंग में एक रेगेक्स को फेंकने से बचें "<a href='foo'>stuff</a>"। आधुनिक रीगेक्स को इससे कोई परेशानी नहीं है।
टॉर्चर

18

सबसे महत्वपूर्ण बात: जब आप जिस भाषा में पार्स कर रहे हैं वह नियमित भाषा नहीं है ।

HTML एक नियमित भाषा नहीं है और इसे नियमित अभिव्यक्ति के साथ पार्स करना संभव नहीं है (केवल कठिन या छोटी गाड़ी कोड के लिए सड़क नहीं है)।


4
गलत! यदि आप किसी भी आधुनिक रेगेक्स फ्लेवर (पर्ल, पीसीआरई, जावा, .NET, ...) का उपयोग कर रहे हैं, तो आप पुनरावृत्ति और अभिकथन कर सकते हैं और इस प्रकार संदर्भ-मुक्त और संदर्भ-संवेदनशील व्याकरण से भी मेल खा सकते हैं।
NikiC

9
@NikiC। गलत नहीं। "आधुनिक रेगेक्स फ्लेवर" नियमित अभिव्यक्ति नहीं हैं (जिसका उपयोग नियमित भाषाओं को पार्स करने के लिए किया जा सकता है, इसलिए नाम)। मैं सहमत हूं कि PRE के साथ आप और अधिक कर सकते हैं, लेकिन मैं उन्हें सिर्फ "नियमित अभिव्यक्ति" नहीं कहूंगा (जैसा मूल प्रश्न में है)।
मट्टियो

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

12

स्टैकओवरफ्लो पर अक्सर लोग देखते हैं कि लोग रेगीज़ के लिए पूछते हैं, जो यह पता लगाते हैं कि क्या किसी दिए गए स्ट्रिंग में यह या वह नहीं है। यह है, IMHO, नियमित अभिव्यक्ति के उद्देश्य को उलट रहा है। यहां तक ​​कि अगर कोई समाधान मौजूद है (नकारात्मक लुकअप एसेसरीज या इस तरह के सामान को नियोजित करना), तो यह अक्सर बेहतर होता है कि इस के लिए रेगेक्स का उपयोग करें और प्रोग्राम लॉजिक के साथ नकारात्मक केस को हैंडल करें।

उदाहरण:

# bad
if (/complicated regex that assures the string does NOT conatin foo|bar/) {
    # do something
}

# appropriate
if (/foo|bar/) {
    # error handling
} else {
    # do something
}

1
+1: कुछ समय, मैंने खुद को रोक कर और खुद से "ठीक है, क्या मैं विशेष रूप से मिलान करने की कोशिश कर रहा हूं?" बजाय "क्या मैं बचने की कोशिश कर रहा हूँ?"

5

दो मामले:

जब एक आसान तरीका है

  • अधिकांश भाषाएँ यह निर्धारित करने के लिए INSTR की तरह एक सरल कार्य प्रदान करती हैं कि क्या एक स्ट्रिंग दूसरे का सबसेट है। यदि आप ऐसा करना चाहते हैं, तो सरल फ़ंक्शन का उपयोग करें। अपनी खुद की नियमित अभिव्यक्ति न लिखें।

  • यदि एक जटिल स्ट्रिंग हेरफेर करने के लिए एक पुस्तकालय उपलब्ध है, तो अपनी नियमित अभिव्यक्ति लिखने के बजाय इसका उपयोग करें।

जब नियमित अभिव्यक्ति पर्याप्त रूप से शक्तिशाली नहीं होती हैं

  • यदि आपको एक पार्सर की आवश्यकता है, तो एक पार्सर का उपयोग करें।

0

नियमित अभिव्यक्तियाँ पुनरावर्ती संरचनाओं की पहचान नहीं कर सकती हैं । यह मौलिक सीमा है।

JSON लें - यह एक बहुत ही सरल प्रारूप है, लेकिन चूंकि किसी ऑब्जेक्ट में अन्य ऑब्जेक्ट हो सकते हैं जैसे कि सदस्य मान (मनमाने ढंग से गहरे), वाक्यविन्यास पुनरावर्ती है और regex द्वारा पार्स नहीं किया जा सकता है। दूसरी ओर CSV को regex'es द्वारा पार्स किया जा सकता है क्योंकि इसमें कोई पुनरावर्ती संरचनाएं नहीं हैं।

कम नियमित अभिव्यक्तियों में पैटर्न को खुद को संदर्भित करने की अनुमति नहीं देता है। आप यह नहीं कह सकते: इस बिंदु पर वाक्यविन्यास पूरे पैटर्न से फिर से मेल खाता है। इसे दूसरे तरीके से रखने के लिए, नियमित अभिव्यक्तियाँ केवल रैखिक रूप से मेल खाती हैं, इसमें एक स्टैक नहीं होता है जो इसे ट्रैक करने की अनुमति देता है कि यह एक नेस्टेड पैटर्न कितना गहरा है।

ध्यान दें कि इससे कोई लेना-देना नहीं है कि प्रारूप कितना जटिल या जटिल है। एस-एक्सप्रेशन वास्तव में बहुत सरल हैं, लेकिन रेक्सक्स के साथ पार्स नहीं किया जा सकता है। दूसरी ओर CSS2 एक सुंदर जटिल भाषा है, लेकिन इसमें पुनरावर्ती संरचनाएं शामिल नहीं हैं और इसके लिए एक rexx के साथ पार्स किया जा सकता है। (हालांकि यह सीएसएस अभिव्यक्तियों के कारण CSS3 के लिए सही नहीं है, जिसमें एक पुनरावर्ती वाक्यविन्यास है।)

इसलिए ऐसा नहीं है क्योंकि यह केवल रेगेक्स का उपयोग करके HTML को पार्स करने के लिए बदसूरत या जटिल या त्रुटि-प्रवण है। यह है कि यह बस संभव नहीं है

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

आमतौर पर इस तरह से पार्सिंग को अलग-अलग चरणों में विभाजित किया जाता है। Tokenization पहला चरण है जहां नियमित अभिव्यक्तियों को "टोकन" के अनुक्रम में विभाजित करने के लिए उपयोग किया जाता है जैसे शब्द, विराम चिह्न, कोष्ठक आदि। पार्सिंग अगला चरण है जहां इन टोकन को एक पदानुक्रमित संरचना, एक सिंटैक्स ट्री में पार्स किया जाता है।

इसलिए जब आप सुनते हैं कि HTML या C # को नियमित अभिव्यक्तियों द्वारा पार्स नहीं किया जा सकता है, तो ध्यान रखें कि नियमित अभिव्यक्ति अभी भी पार्सर्स का एक महत्वपूर्ण हिस्सा है। आप केवल नियमित अभिव्यक्ति और कोई सहायक कोड का उपयोग करके ऐसी भाषा को पार्स नहीं कर सकते ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.