Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Ruby

रूबी पार्सिंग में मास्टर करें: स्क्रैच से अपना खुद का पार्सर बनाएं

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

उदाहरण के लिए, यह सामान्य ज्ञान है कि HTML को रेगुलर एक्सप्रेशन्स से पार्स करना शायद एक अच्छा विचार नहीं है।

रूबी में हमारे पास नोकोगिरी है जो यह काम हमारे लिए कर सकता है, लेकिन आप अपना खुद का पार्सर बनाकर बहुत कुछ सीख सकते हैं। आइए शुरू करें!

रूबी के साथ पार्सिंग

हमारे पार्सर का मूल StringScanner क्लास है।

यह क्लास एक स्ट्रिंग की कॉपी और एक पोजीशन पॉइंटर रखती है। पॉइंटर हमें कुछ टोकन्स की खोज में स्ट्रिंग को पार करने की अनुमति देगा।

हम जिन विधियों का उपयोग करेंगे वे हैं:

  • .peek
  • .scan_until
  • .getch

एक और उपयोगी विधि है .scan (बिना until के)।

नोट:

यदि StringScanner आपके लिए उपलब्ध नहीं है तो require 'strscan' जोड़ने का प्रयास करें।

मैंने दो टेस्ट डॉक्यूमेंटेशन के रूप में लिखे हैं ताकि हम समझ सकें कि यह क्लास कैसे काम करती है:

 describe StringScanner do let (:buff) { StringScanner.new "testing" } it "can peek one step ahead" do expect(buff.peek 1).to eq "t" end it "can read one char and return it" do expect(buff.getch).to eq "t" expect(buff.getch).to eq "e" end end 

इस क्लास के बारे में ध्यान देने वाली एक महत्वपूर्ण बात यह है कि कुछ विधियाँ पोजीशन पॉइंटर को आगे बढ़ाती हैं (getch, scan), जबकि अन्य नहीं (peek)। किसी भी बिंदु पर आप अपने स्कैनर का निरीक्षण कर सकते हैं (.inspect या p का उपयोग करके) यह देखने के लिए कि यह कहां है।

पार्सर क्लास

पार्सर क्लास वह जगह है जहां अधिकांश काम होता है, हम इसे उस टेक्स्ट के स्निपेट के साथ इनिशियलाइज़ करेंगे जिसे हम पार्स करना चाहते हैं और यह उसके लिए एक StringScanner बनाएगा और पार्स विधि को कॉल करेगा:

 def initialize(str) @buffer = StringScanner.new(str) @tags = [] parse end

टेस्ट में हम इसे इस तरह परिभाषित करते हैं:

 let(:parser) { Parser.new "<body>testing</body> <title>parsing with ruby</title>" }

हम थोड़ी देर में देखेंगे कि यह क्लास अपना काम कैसे करती है, लेकिन पहले आइए हमारे प्रोग्राम के अंतिम भाग पर एक नज़र डालते हैं।

टैग क्लास

यह क्लास बहुत सरल है, यह मुख्य रूप से पार्सिंग परिणामों के लिए एक कंटेनर और डेटा क्लास के रूप में कार्य करती है।

 class Tag attr_reader :name attr_accessor :content def initialize(name) @name = name end end 

आइए पार्स करें!

किसी चीज़ को पार्स करने के लिए हमें अपने इनपुट टेक्स्ट को देखकर पैटर्न ढूंढने होंगे। उदाहरण के लिए, हम जानते हैं कि HTML कोड का निम्नलिखित रूप होता है:

<tag>contents</tag>

यहां स्पष्ट रूप से दो अलग-अलग घटक हैं जिन्हें हम पहचान सकते हैं, टैग नाम और टैग्स के अंदर का टेक्स्ट। यदि हम BNF नोटेशन का उपयोग करके एक औपचारिक व्याकरण को परिभाषित करते तो यह कुछ इस तरह दिखता:

 tag = <opening_tag> <contents> <closing_tag> opening_tag = "<" <tag_name> ">" closing_tag = "</" <tag_name> ">" 

हम StringScanner के peek का उपयोग यह देखने के लिए करेंगे कि क्या हमारे इनपुट बफर पर अगला सिंबल एक ओपनिंग टैग है। यदि ऐसा है तो हम अपने पार्सर क्लास पर find_tag और find_content विधियों को कॉल करेंगे:

 def parse_element if @buffer.peek(1) == '<' @tags << find_tag last_tag.content = find_content end end 

find_tag विधि होगी:

  • ओपनिंग टैग कैरेक्टर को 'कंज्यूम' करना
  • क्लोजिंग सिंबल (">") मिलने तक स्कैन करना
  • टैग नाम के साथ एक नया Tag ऑब्जेक्ट बनाना और वापस करना

यहां कोड है, ध्यान दें कि हमें अंतिम कैरेक्टर को चॉप करना होगा। ऐसा इसलिए है क्योंकि scan_until परिणामों में '>' को शामिल करता है, और हम वह नहीं चाहते।

 def find_tag @buffer.getch tag = @buffer.scan_until />/ Tag.new(tag.chop) end 

अगला कदम टैग के अंदर की सामग्री को ढूंढना है, यह बहुत कठिन नहीं होना चाहिए क्योंकि scan_until विधि पोजीशन पॉइंटर को सही स्थान पर आगे बढ़ाती है। हम क्लोजिंग टैग को ढूंढने और टैग सामग्री वापस करने के लिए फिर से scan_until का उपयोग करने जा रहे हैं।

रूबी पार्सिंग में मास्टर करें: स्क्रैच से अपना खुद का पार्सर बनाएं

def find_content tag = last_tag.name content = @buffer.scan_until /<\/#{tag}>/ content.sub("</#{tag}>", "") end 

अब:

हमें बस parse_element को एक लूप में कॉल करना है जब तक कि हम अपने इनपुट बफर पर और टैग न ढूंढ सकें।

def parse until @buffer.eos? skip_spaces parse_element end end 

आप पूरा कोड यहां पा सकते हैं: https://github.com/matugm/simple-parser। आप नेस्टेड टैग्स को संभालने वाले विस्तारित संस्करण के लिए 'nested_tags' ब्रांच भी देख सकते हैं।

निष्कर्ष

पार्सर लिखना एक दिलचस्प विषय है और यह कई बार काफी जटिल हो सकता है।

यदि आप स्क्रैच से अपना खुद का पार्सर नहीं बनाना चाहते हैं तो आप तथाकथित 'पार्सर जनरेटर्स' में से एक का उपयोग कर सकते हैं। रूबी में हमारे पास ट्रीटॉप और पार्सलेट हैं।

  1. Ruby के Map मेथड में महारत: उदाहरणों के साथ एक व्यावहारिक गाइड Ruby के Map मेथड में महारत: उदाहरणों के साथ एक व्यावहारिक गाइड

    Map एक Ruby मेथड है जिसका उपयोग आप Arrays, Hashes और Ranges के साथ कर सकते हैं। map का मुख्य उपयोग डेटा को ट्रांसफॉर्म करना है। उदाहरण के लिए: स्ट्रिंग्स की एक सरणी दिए जाने पर, आप हर स्ट्रिंग पर जा सकते हैं और हर कैरेक्टर को UPPERCASE बना सकते हैं। या यदि आपके पास User ऑब्जेक्ट्स की एक सूची है... आ

  1. रूबी में फाइलें कैसे पढ़ें और लिखें: एक चरण-दर-चरण गाइड रूबी में फाइलें कैसे पढ़ें और लिखें: एक चरण-दर-चरण गाइड

    आज आप सीखेंगे कि रूबी में फाइलें कैसे पढ़ें और लिखें ताकि आप सामग्री निकाल सकें, नई फाइलें बना सकें, और वह जानकारी ढूंढ सकें जिसकी आपको आवश्यकता है! यहां हम क्या कवर करने जा रहे हैं: विषयसूची1 रूबी में फाइलें कैसे पढ़ें2 रूबी में फाइल में कैसे लिखें3 रूबी फाइल मेथड्स4 डायरेक्टरी ऑपरेशन्स5 FileUtils

  1. SwiftUI के साथ एक मजबूत डिजाइन सिस्टम बनाना: एक पूर्ण गाइड SwiftUI के साथ एक मजबूत डिजाइन सिस्टम बनाना: एक पूर्ण गाइड

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