नियमित अभिव्यक्ति समूह क्या हैं?


91

मैं बस एक सवाल पढ़ रहा था कि डबल घुंघराले ब्रेसिज़ ( यह सवाल ) के अंदर डेटा कैसे प्राप्त किया जाए , और फिर किसी ने संतुलन समूहों को लाया। मुझे अभी भी यकीन नहीं है कि वे क्या हैं और उनका उपयोग कैसे करें।

मैं बैलेंसिंग ग्रुप डेफिनिशन के माध्यम से पढ़ता हूं , लेकिन स्पष्टीकरण का पालन करना कठिन है, और मैं अभी भी उन सवालों पर काफी उलझन में हूं, जिनका मैंने उल्लेख किया था।

क्या कोई यह बता सकता है कि संतुलन वाले समूह क्या हैं और वे कैसे उपयोगी हैं?


मुझे आश्चर्य है कि यह वास्तव में कितने रेगेक्स एंगिएंस का समर्थन करता है।
माइक डी क्लार्क

2
@MikedeKlerk यह कम से कम .NET रेगेक्स इंजन में समर्थित है।
इट्नोटली।

जवाबों:


173

जहाँ तक मुझे पता है, .NET के regex फ्लेवर के लिए बैलेंसिंग ग्रुप्स अद्वितीय हैं।

एक तरफ: बार-बार समूह

सबसे पहले, आपको यह जानना होगा कि .NET है (फिर, जहाँ तक मुझे पता है) एकमात्र रेगीक्स स्वाद है जो आपको एक कैप्चरिंग ग्रुप के कई कैप्चर एक्सेस करने देता है (बैकरेफेर में नहीं लेकिन मैच पूरा होने के बाद)।

एक उदाहरण के साथ यह समझाने के लिए, पैटर्न पर विचार करें

(.)+

और स्ट्रिंग "abcd"

अन्य सभी रेगेक्स फ्लेवर में, कैप्चरिंग ग्रुप 1केवल एक परिणाम देगा: d(ध्यान दें, पूर्ण मैच निश्चित abcdरूप से अपेक्षित होगा)। ऐसा इसलिए है क्योंकि कैप्चरिंग ग्रुप का हर नया उपयोग पिछली कैप्चर को ओवरराइट कर देता है।

दूसरी ओर .NET उन सभी को याद करता है। और यह एक स्टैक में ऐसा करता है। उपरोक्त रेगेक्स की तरह मिलान करने के बाद

Match m = new Regex(@"(.)+").Match("abcd");

तुम पाओगे कि

m.Groups[1].Captures

एक है CaptureCollectionचार कैप्चर करने के लिए जिसका तत्वों अनुरूप

0: "a"
1: "b"
2: "c"
3: "d"

जहां संख्या सूचकांक में है CaptureCollection। इसलिए मूल रूप से हर बार जब समूह का फिर से उपयोग किया जाता है, तो एक नया कब्जा स्टैक पर धकेल दिया जाता है।

यह और अधिक दिलचस्प हो जाता है अगर हम नामांकित समूहों का उपयोग कर रहे हैं। क्योंकि .NET उसी नाम का बार-बार उपयोग करने की अनुमति देता है, जैसे हम एक regex लिख सकते हैं

(?<word>\w+)\W+(?<word>\w+)

एक ही समूह में दो शब्दों को पकड़ने के लिए। फिर, हर बार एक निश्चित नाम वाला एक समूह सामने आता है, एक कैप्चर को उसके स्टैक पर धकेल दिया जाता है। तो इस रेगेक्स को इनपुट पर लागू करना "foo bar"और निरीक्षण करना

m.Groups["word"].Captures

हम दो कैद पाते हैं

0: "foo"
1: "bar"

यह हमें अभिव्यक्ति के विभिन्न हिस्सों से एक ही ढेर पर चीजों को धक्का देने की भी अनुमति देता है। लेकिन फिर भी, यह केवल .NET की विशेषता है जो कई कैप्चर को ट्रैक करने में सक्षम है जो इसमें सूचीबद्ध हैं CaptureCollection। लेकिन मैंने कहा, यह संग्रह एक ढेर है । तो क्या हम इससे चीजों को पॉप कर सकते हैं ?

दर्ज करें: संतुलन समूह

यह पता चलता है कि हम कर सकते हैं। यदि हम जैसे एक समूह का उपयोग करते हैं (?<-word>...), तो अंतिम कैप्चर को स्टैक से पॉपअप किया जाता है wordयदि उपप्रकारकता ...मेल खाता है। इसलिए अगर हम अपनी पिछली अभिव्यक्ति को बदलते हैं

(?<word>\w+)\W+(?<-word>\w+)

फिर दूसरा समूह पहले समूह के कैप्चर को पॉप करेगा, और हम CaptureCollectionअंत में एक खाली प्राप्त करेंगे । बेशक, यह उदाहरण बहुत बेकार है।

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

^(?:[^()]|(?<Open>[(])|(?<-Open>[)]))*$

इसलिए हमारे पास एक पुनरावृत्ति में तीन विकल्प हैं। पहला विकल्प सब कुछ खा जाता है जो कोष्ठक नहीं है। (स्टैक पर उन्हें धकेलते हुए दूसरा वैकल्पिक मैच । )स्टैक से तत्वों को पॉप करते समय तीसरा वैकल्पिक मिलान होता है (यदि संभव हो!)।

नोट: बस स्पष्ट करने के लिए, हम केवल जाँच रहे हैं कि कोई बेजोड़ कोष्ठक नहीं हैं! इसका मतलब है कि सब पर कोई कोष्ठकों युक्त स्ट्रिंग होगा , से मेल खाते हैं क्योंकि वे अभी भी वाक्य रचना मान्य हैं (कुछ वाक्य रचना जहां मैच करने के लिए अपने कोष्ठकों की जरूरत है)। यदि आप कोष्ठक के कम से कम एक सेट को सुनिश्चित करना चाहते हैं, तो बस इसके (?=.*[(])बाद एक लुकहेड जोड़ें ^

यह पैटर्न हालांकि सही (या पूरी तरह सही) नहीं है।

समापन: सशर्त पैटर्न

एक और पकड़ है: यह सुनिश्चित नहीं करता है कि स्ट्रिंग के अंत में स्टैक खाली है (इसलिए (foo(bar)मान्य होगा)। .NET (और कई अन्य स्वादों) में एक और निर्माण है जो हमें यहां मदद करता है: सशर्त पैटर्न। सामान्य वाक्यविन्यास है

(?(condition)truePattern|falsePattern)

जहां falsePatternवैकल्पिक है - अगर इसे छोड़ दिया जाता है तो झूठे केस हमेशा मेल खाएगा। हालत या तो एक पैटर्न, या एक कैप्चरिंग ग्रुप का नाम हो सकता है। मैं यहाँ बाद वाले मामले पर ध्यान केंद्रित करूँगा। यदि यह एक कैप्चरिंग ग्रुप का नाम है, तो truePatternइसका उपयोग तब किया जाता है जब और केवल उस विशेष समूह के लिए कैप्चर स्टैक खाली न हो। यही है, एक सशर्त पैटर्न (?(name)yes|no)पढ़ता है "अगर nameमिलान किया है और कुछ पर कब्जा कर लिया है (जो अभी भी स्टैक पर है), पैटर्न का yesउपयोग करें अन्यथा पैटर्न no"।

इसलिए हमारे उपरोक्त पैटर्न के अंत में हम कुछ ऐसा जोड़ सकते हैं (?(Open)failPattern)जिसके कारण संपूर्ण पैटर्न विफल हो जाता है, अगर Open-स्टैक खाली नहीं है। पैटर्न को बिना शर्त विफल बनाने के लिए सबसे सरल बात है (?!)(एक खाली नकारात्मक लुकहेड)। तो हमारे पास हमारा अंतिम पैटर्न है:

^(?:[^()]|(?<Open>[(])|(?<-Open>[)]))*(?(Open)(?!))$

ध्यान दें कि इस सशर्त सिंटैक्स का संतुलन समूहों के साथ कुछ भी नहीं है, लेकिन उनकी पूरी शक्ति का उपयोग करना आवश्यक है।

यहाँ से, आकाश की सीमा है। कई बहुत परिष्कृत उपयोग संभव हैं और चर-लंबाई के रूप में अन्य .NET-Regex सुविधाओं के साथ संयोजन में उपयोग किए जाने पर कुछ गोच हो जाते हैं ( जो मुझे स्वयं कठिन तरीका सीखना था )। हालांकि मुख्य सवाल यह है कि क्या इन सुविधाओं का उपयोग करते समय आपका कोड अभी भी बनाए रखा जा सकता है? आपको इसे वास्तव में अच्छी तरह से प्रलेखित करने की आवश्यकता है, और सुनिश्चित करें कि हर कोई जो इस पर काम करता है, वह इन विशेषताओं के बारे में भी जानता है। अन्यथा आप बेहतर बंद हो सकते हैं, बस स्ट्रिंग को मैन्युअल रूप से चरित्र-दर-चरित्र चलना और एक पूर्णांक में घोंसले के शिकार के स्तर की गणना करना।

परिशिष्ट: (?<A-B>...)वाक्य रचना के साथ क्या है ?

इस भाग का श्रेय कोबी को जाता है (अधिक विवरण के लिए नीचे उसका उत्तर देखें)।

अब उपरोक्त सभी के साथ, हम पुष्टि कर सकते हैं कि एक स्ट्रिंग सही ढंग से कोष्ठक है। लेकिन यह बहुत अधिक उपयोगी होगा, अगर हम उन सभी कोष्ठकों की सामग्री के लिए वास्तव में प्राप्त कर सकते हैं (नेस्टेड)। बेशक, हम एक अलग कैप्चर स्टैक में कोष्ठक खोलने और बंद करने को याद कर सकते हैं जो खाली नहीं है, और फिर एक अलग चरण में उनके स्थान के आधार पर कुछ प्रतिस्थापन निष्कर्षण करते हैं।

लेकिन .NET यहां एक और सुविधा सुविधा प्रदान करता है: यदि हम उपयोग करते हैं (?<A-B>subPattern), तो न केवल स्टैक से कैप्चर किया गया पॉप है B, बल्कि पॉप-अप कैप्चर के बीच सब कुछ है Bऔर यह वर्तमान समूह स्टैक पर धकेल दिया जाता है A। इसलिए यदि हम समापन कोष्ठक के लिए इस तरह के एक समूह का उपयोग करते हैं, तो हमारे स्टैक से घोंसले के स्तर को पॉप करते हुए, हम जोड़ी की सामग्री को दूसरे स्टैक पर भी धकेल सकते हैं:

^(?:[^()]|(?<Open>[(])|(?<Content-Open>[)]))*(?(Open)(?!))$

कोबी ने अपने जवाब में यह लाइव-डेमो प्रदान किया

इसलिए इन सभी चीजों को एक साथ लेकर हम कर सकते हैं:

  • मनमाने ढंग से कई कैद याद रखें
  • नेस्टेड संरचनाओं को मान्य करें
  • प्रत्येक घोंसले के स्तर पर कब्जा

सभी एक ही नियमित अभिव्यक्ति में। यदि यह रोमांचक नहीं है ...);

जब मैंने पहली बार उनके बारे में सीखा तो कुछ संसाधन मुझे मददगार लगे:


6
इस उत्तर को "एडवांस्ड रेगेक्स-फू" के तहत स्टैक ओवरफ्लो रेगुलर एक्सप्रेशंस एफएक्यू में जोड़ा गया है ।
aliteralmind

39

एम। Buettner के उत्कृष्ट जवाब के लिए बस एक छोटा सा जोड़:

(?<A-B>)वाक्य रचना के साथ क्या हुआ है ?

(?<A-B>x)से बिल्कुल अलग है (?<-A>(?<B>x))। वे एक ही नियंत्रण प्रवाह * में परिणाम करते हैं , लेकिन वे अलग तरीके से कब्जा करते हैं।
उदाहरण के लिए, आइए संतुलित ब्रेसेस के लिए एक पैटर्न देखें:

(?:[^{}]|(?<B>{)|(?<-B>}))+(?(B)(?!))

मैच के अंत में हमारे पास एक संतुलित स्ट्रिंग है, लेकिन हमारे पास यह सब है - हमें नहीं पता कि ब्रेस कहां हैं क्योंकि Bस्टैक खाली है। इंजन ने हमारे लिए जो मेहनत की है वह खत्म हो चुकी है।
( रेगेक्स स्टॉर्म पर उदाहरण )

(?<A-B>x)उस समस्या का हल है। कैसे? इसमें कब्जा नहींx है $A: यह पिछली कैप्चर Bऔर वर्तमान स्थिति के बीच की सामग्री को कैप्चर करता है ।

चलो इसे हमारे पैटर्न में उपयोग करते हैं:

(?:[^{}]|(?<Open>{)|(?<Content-Open>}))+(?(Open)(?!))

यह $Contentब्रेसिज़ (और उनकी स्थिति) के बीच के तारों में कब्जा कर लेगा , रास्ते में प्रत्येक जोड़ी के लिए।
स्ट्रिंग के लिए {1 2 {3} {4 5 {6}} 7}वहाँ हो जाएगा चार कैप्चर: 3, 6, 4 5 {6}, और 1 2 {3} {4 5 {6}} 7- ज्यादा से बेहतर कुछ भी नहीं है या } } } }
( उदाहरण - tableटैब पर क्लिक करें और देखें ${Content}, कैप्चर करें )

वास्तव में, इसका उपयोग बिना संतुलन के किया जा सकता है: (?<A>).(.(?<Content-A>).)पहले दो पात्रों को पकड़ता है, भले ही वे समूहों द्वारा अलग हो गए हों।
(एक लुकहेड का उपयोग आमतौर पर यहां किया जाता है, लेकिन यह हमेशा पैमाने पर नहीं होता है: यह आपके तर्क की नकल कर सकता है।)

(?<A-B>)एक मजबूत विशेषता है - यह आपको अपनी कैद पर सटीक नियंत्रण देता है । ध्यान रखें कि जब आप अपने पैटर्न से बाहर निकलने की कोशिश कर रहे हों।


@FYI, उस प्रश्न से चर्चा जारी रखना जो आप इस एक नए उत्तर में पसंद नहीं करते । :)
zx81

मैं स्ट्रिंग्स के अंदर ब्रेसिज़ से बचने के साथ संतुलित ब्रेसिज़ रेगेक्स जांच करने का एक तरीका निकालने की कोशिश कर रहा हूं। ईजी निम्न कोड पास करेगा: सार्वजनिक वर्ग फू {निजी कांस्टेबल बार = '{'; निजी स्ट्रिंग _qux = "{{{"; } क्या किसी ने ऐसा किया है?
श्री एंडरसन

@MrAnderson - आपको बस |'[^']*'सही जगह जोड़ने की जरूरत है: उदाहरण । यदि आपको बच गए पात्रों की भी आवश्यकता है, तो यहां एक उदाहरण है: (सी # स्ट्रिंग शाब्दिक मिलान के लिए Rexx) [ stackoverflow.com/a/4953878/7586]
कोबी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.