2010-09-03 21 views
60

प्रोग्रामिंग के वर्षों के बाद भी, मुझे यह कहने में शर्म आती है कि मैंने कभी भी पूरी तरह से नियमित अभिव्यक्तियों को पूरी तरह से समझ नहीं लिया है। आम तौर पर, जब कोई समस्या रेगेक्स के लिए कॉल करती है, तो मैं आमतौर पर (सिंटैक्स का जिक्र करने के समूह के बाद) उपयुक्त हो सकता हूं, लेकिन यह एक ऐसी तकनीक है जिसे मैं अपने आप को तेजी से उपयोग कर पाता हूं।नियमित अभिव्यक्तियों के लिए एक पार्सर लिखना

तो, मुझे खुद को सिखाने और नियमित अभिव्यक्तियों को समझने के लिए ठीक से, मैंने कुछ सीखने का प्रयास करते समय हमेशा ऐसा करने का निर्णय लिया है; यानी, कुछ महत्वाकांक्षी लिखने का प्रयास करें कि जैसे ही मुझे लगता है कि मैंने पर्याप्त सीखा है, मैं शायद त्याग दूंगा।

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

सवाल यह है कि, मैं कहां से शुरू करूं? मैं लगभग कुछ भी नहीं जानता कि रेगेक्स को पार्स किया गया है और इस तथ्य से अलग व्याख्या की गई है कि इसमें किसी भी तरह से एक सीमित राज्य automaton शामिल है। इस बल्कि चुनौतीपूर्ण समस्या से संपर्क करने के लिए कोई सुझाव बहुत सराहना की जाएगी।

संपादित करें:। मैं स्पष्ट करना चाहिए कि जब तक मैं लिए जा रहा हूँ लागू अजगर में regex पार्सर, मैं क्या प्रोग्रामिंग भाषा उदाहरण या लेख में लिखा जाता है के बारे में बहुत ज्यादा परेशान नहीं कर रहा हूँ जब तक यह नहीं है के रूप में ब्रेनफक में, मैं शायद इसे अपने समय के लायक बनाने के लिए पर्याप्त समझूंगा।

+0

+1 दिलचस्प विचार। यदि आप इसे प्राप्त करते हैं तो आप रेगेक्स में विशेषज्ञ होंगे;) –

+2

[रोचक] (http://www.codeproject.com/KB/recipes/OwnRegExpressionsParser.aspx#Seven) एक सरलीकृत आरई पार्सर बनाने के तरीके पर आलेख नहीं (नहीं हालांकि पाइथन संबंधित) – systempuntoout

+2

http://perl.plover.com/Regex/article.html ऑटोटाटा का उपयोग कर रेगेक्स इंजन का एक स्पष्टीकरण है। आप यहां एक सरल परियोजना पर भी विचार करना चाहेंगे जो कुछ समय पहले उठाया गया था, जो एक रेगेक्स-टू-इंग्लिश अनुवादक लिखना है। उदाहरण के लिए, '(foo | bar) (baz) +' को 'या तो "foo" या बार "फिर एक या अधिक" baz "में अनुवाद करना चाहिए। पाइपर्सिंग (http://pyparsing.wikispaces.com/Documentation) मदद कर सकता है इसके साथ। – katrielalex

उत्तर

34

एक नियमित अभिव्यक्ति इंजन के कार्यान्वयन को लिखना वास्तव में एक जटिल कार्य है।

लेकिन अगर आप इसे कैसे करना करने में रुचि रखते हैं, भले ही आप वास्तव में इसे लागू करने के विवरण की पर्याप्त समझ में नहीं कर सकते हैं, मैं सुझाव है कि आप कम से कम इस लेख को देखो:

Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby, ...)

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

+1

+1, awesom लेख। – Claudiu

+1

यह एक अविश्वसनीय लेख है। मैं इसके माध्यम से आधे रास्ते में हूं, और मैं पहले से ही अपने सिर में कोड लेने वाला कोड देख रहा हूं! –

+2

@ चिन्मय कांची: उस आलेख के लेखक ने नियमित अभिव्यक्तियों पर कुछ अन्य लेख भी लिखे हैं। यह भी बहुत दिलचस्प है: http://swtch.com/~rsc/regexp/regexp3.html और अधिकतर उन्नत नियमित अभिव्यक्ति इंजनों का समर्थन करने वाली कुछ और उन्नत सुविधाओं को कार्यान्वित करने के तरीके के बारे में अधिक जानकारी देता है। –

4

ब्रायन कर्निघन द्वारा Beautiful Code में एक दिलचस्प (यदि थोड़ा छोटा) अध्याय है, जिसे उचित रूप से "ए रेग्युलर एक्सप्रेशन मैचर" कहा जाता है। इसमें उन्होंने एक साधारण मैचर पर चर्चा की जो शाब्दिक पात्रों से मेल खा सकता है, और .^$* प्रतीकों से मेल खाता है।

6

This paper एक दिलचस्प दृष्टिकोण लेता है। कार्यान्वयन हास्केल में दिया गया है, लेकिन यह कम से कम एक बार reimplemented in Python रहा है।

+0

बहुत बढ़िया लेख! –

19

मैंने मार्क बेयर्स को पहले से ही एक +1 दिया है - लेकिन जहां तक ​​मुझे याद है कि पेपर वास्तव में यह नहीं कहता है कि नियमित अभिव्यक्ति मिलान कैसे समझाता है कि एक एल्गोरिदम खराब क्यों है और दूसरा बेहतर है। शायद लिंक में कुछ?

मैं अच्छे दृष्टिकोण पर ध्यान केंद्रित करूंगा - सीमित ऑटोमाटा बनाना। यदि आप स्वयं को निर्धारित करने के लिए निर्धारिती ऑटोमाटा तक सीमित करते हैं, तो यह वास्तव में बहुत मुश्किल नहीं है।

Modern Compiler Design में लिया गया दृष्टिकोण क्या है (बहुत तेज़ी से) वर्णन करता हूं।

कल्पना कीजिए कि आप निम्नलिखित नियमित अभिव्यक्ति है ...

a (b c)* d 

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

0 : .a (b c)* d 

ही संभव मैच 'एक' है, इसलिए अगले राज्य हम निकाले जाते है। ..

1 : a.(b c)* d 

अब हम दो संभावनाएं है - 'बी' से मेल खाते हैं (हो, तो की 'बी सी' कम से कम एक दोहराने) या मेल खाते हैं 'प' अन्यथा। नोट - हम मूल रूप से यहां एक डिग्राफ खोज कर रहे हैं (या तो गहराई पहले या चौड़ाई पहले या जो भी हो) लेकिन हम इसे खोजते समय डिग्राफ की खोज कर रहे हैं। एक चौड़ाई वाली पहली रणनीति मानते हुए, हमें बाद में विचार करने के लिए हमारे मामलों में से एक को कतारबद्ध करने की आवश्यकता होगी, लेकिन मैं यहां से उस मुद्दे को अनदेखा कर दूंगा। वैसे भी, हमने दो नए राज्यों की खोज की है ...

2 : a (b.c)* d 
3 : a (b c)* d. 

राज्य 3 एक अंत राज्य है (एक से अधिक हो सकता है)। राज्य 2 के लिए, हम केवल 'सी' से मेल खाते हैं, लेकिन हमें बाद में डॉट स्थिति से सावधान रहना होगा। हमें "ए। (बी सी) * डी" मिलता है - जो राज्य 1 जैसा ही है, इसलिए हमें एक नई स्थिति की आवश्यकता नहीं है।

आईआईआरसी, आधुनिक कंपाइलर डिज़ाइन में दृष्टिकोण डॉट के हैंडलिंग को सरल बनाने के लिए, ऑपरेटर को दबाते समय एक नियम का अनुवाद करना है। राज्य 1 में तब्दील किया जाएगा ...

1 : a.b c (b c)* d 
    a.d 

है, अपने अगले विकल्प या तो पहले पुनरावृत्ति मैच के लिए या पुनरावृत्ति को छोड़ने के लिए है। इसके अगले राज्य राज्यों 2 और 3 के बराबर हैं। इस दृष्टिकोण का एक लाभ यह है कि आप अपने सभी पिछले मैचों ('।' से पहले सब कुछ छोड़ सकते हैं) क्योंकि आप केवल भविष्य के मैचों की परवाह करते हैं। यह आम तौर पर एक छोटा राज्य मॉडल देता है (लेकिन जरूरी नहीं कि कम से कम एक)।

संपादित करें यदि आप पहले से मिलान किए गए विवरण को छोड़ देते हैं, तो आपका राज्य विवरण स्ट्रिंग्स के सेट का प्रतिनिधित्व है जो इस बिंदु से हो सकता है।

अमूर्त बीजगणित के संदर्भ में, यह एक प्रकार का सेट बंद है। एक बीजगणित मूल रूप से एक (या अधिक) ऑपरेटरों के साथ एक सेट है। हमारा सेट राज्य के विवरणों का है, और हमारे ऑपरेटर हमारे संक्रमण (चरित्र मिलान) हैं। एक बंद सेट वह है जहां सेट में किसी भी सदस्य को कोई भी ऑपरेटर लागू करना हमेशा सेट में मौजूद एक अन्य सदस्य का उत्पादन करता है। एक सेट को बंद करना सबसे बड़ा सेट है जो बंद है। तो मूल रूप से, स्पष्ट प्रारंभ स्थिति से शुरू होने पर, हम उन राज्यों के न्यूनतम सेट का निर्माण कर रहे हैं जो संक्रमण ऑपरेटर के हमारे सेट के सापेक्ष बंद हैं - पहुंचने योग्य राज्यों का न्यूनतम सेट।

यहां न्यूनतम बंद प्रक्रिया को संदर्भित करता है - वहां एक छोटा समकक्ष ऑटोमाटा हो सकता है जिसे सामान्य रूप से न्यूनतम कहा जाता है।

इस मूल विचार को ध्यान में रखते हुए, यह कहना मुश्किल नहीं है कि "अगर मेरे पास स्ट्रिंग के दो सेट का प्रतिनिधित्व करने वाली दो राज्य मशीनें हैं, तो मैं संघ का प्रतिनिधित्व करने वाले तीसरे को कैसे प्राप्त करूं" (या चौराहे, या सेट अंतर ...)। बिंदीदार नियमों के बजाय, आपके राज्य के प्रतिनिधित्व प्रत्येक इनपुट automaton और शायद अतिरिक्त विवरण से वर्तमान स्थिति (या मौजूदा राज्यों का सेट) होगा।

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

होपक्रॉफ्ट्स एल्गोरिदम इस मूल विचार को संभालने का एक प्रभावी तरीका है।

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

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

बीटीडब्ल्यू - शेष Dick Grunes site के आसपास एक नज़र डालें - उसके पास पार्सिंग तकनीकों पर एक मुफ्त पीडीएफ पुस्तक है। मॉडर्न कंपाइलर डिज़ाइन का पहला संस्करण बहुत अच्छा आईएमओ है, लेकिन जैसा कि आप देखेंगे, दूसरा संस्करण आसन्न है।

+0

जॉन फिक्सेस के लिए धन्यवाद। – Steve314

+1

यह चाल एलआर पार्सर्स उत्पन्न करने के लिए उपयोग की जाने वाली एक ही विधि है: व्याकरण नियमों के सेट के माध्यम से पार्सर स्टेट का प्रतिनिधित्व करने वाले धक्का बिंदु। बिंदीदार नियम पार्स राज्यों का प्रतिनिधित्व करते हैं। –

+0

अच्छा जवाब। एफवाईआई, आधुनिक कंपाइलर डिजाइन का लिंक टूटा हुआ है। – rvighne

0

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

+2

वह उद्देश्य को हर तरह से पराजित करेगा, है ना? –

+0

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

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