2013-07-18 7 views
5

मैं एकाधिक लाइनों पार्सलेट से मेल खाने का एक तरीका ढूंढ रहा हूं। कोड इस तरह दिखता है:रूबी अजमोद: एकाधिक रेखाओं को पार्सिंग

rule(:line) { (match('$').absent? >> any).repeat >> match('$') } 
rule(:lines) { line.repeat } 

हालांकि, lines हमेशा ऊपर अनंत लूप है जो क्योंकि match('$') अंतहीन स्ट्रिंग के अंत से मिलान करने के दोहराएँगे में खत्म हो जाएगा।

क्या खाली हो सकता है कि कई लाइनों से मेल खाना संभव है?

irb(main)> lines.parse($stdin.read) 
This 
is 

a 
multiline 

string^D 

सफलतापूर्वक मेल खाना चाहिए। क्या मैं कुछ भूल रहा हूँ? मैंने (match('$').absent? >> any.maybe).repeat(1) >> match('$') भी कोशिश की लेकिन यह खाली लाइनों से मेल नहीं खाता है।

सम्मान,
डैनियल।

उत्तर

3

मुझे लगता है कि आप दो, संबंधित, अपने मिलान समस्याएं आ रही हैं:

  • छद्म चरित्र मैच $ किसी भी वास्तविक पात्रों का उपभोग नहीं करता है। आपको अभी भी किसी भी तरह की न्यूलाइन का उपभोग करने की आवश्यकता है।

  • पार्सलेट कुछ तरीकों से इनपुट को घुमा रहा है, जिससे $ उन जगहों पर मिलान कर सकता है जहां आप उम्मीद नहीं कर सकते हैं। $ का उपयोग करके मुझे प्राप्त होने वाला सबसे अच्छा परिणाम प्रत्येक व्यक्तिगत चरित्र से मेल खाता है।

\n का उपयोग अंतराल के चरित्र के रूप में करने के लिए अधिक सुरक्षित है। मैं काम करने के लिए (मैं, Parslet अपने आप के साथ एक शुरुआत के कुछ कर रहा हूँ तो क्षमा याचना करता है, तो यह स्पष्ट हो सकता है) निम्नलिखित है:

require 'parslet' 

class Lines < Parslet::Parser 
    rule(:text) { match("[^\n]") } 
    rule(:line) { (text.repeat(0) >> match("\n")) | text.repeat(1) } 
    rule(:lines) { line.as(:line).repeat } 
    root :lines 
end 

s = "This 
is 

a 
multiline 
string" 

p Lines.new.parse(s) 

लाइन के लिए नियम और जरूरत एक खाली लाइनों से मिलान करने की वजह से जटिल है \n के बिना संभव अंतिम पंक्ति।

आपको .as(:line) वाक्यविन्यास का उपयोग करने की आवश्यकता नहीं है - मैंने इसे स्पष्ट रूप से दिखाने के लिए जोड़ा है कि :line नियम प्रत्येक पंक्ति को व्यक्तिगत रूप से मेल खाता है, और केवल पूरे इनपुट का उपभोग नहीं करता है।

+0

यह एक अच्छा समाधान की तरह दिखता है। मेरा कामकाज अंत में मैच विफलता को रोकने के लिए '\ n' के साथ भी काम करना था और आने वाली स्ट्रिंग में एक नई लाइन जोड़ने के लिए था। हालांकि, यह क्लीनर दिखता है। धन्यवाद! – Danyel

6

मैं आमतौर पर end_of_line के लिए नियम परिभाषित करता हूं। यह end_of_file से मेल खाने के लिए http://kschiess.github.io/parslet/tricks.html में चाल पर आधारित है।

class MyParser < Parslet::Parser 
    rule(:cr)   { str("\n") } 
    rule(:eol?)  { any.absent? | cr } 
    rule(:line_body) { (eol?.absent? >> any).repeat(1) } 
    rule(:line)  { cr | line_body >> eol? } 
    rule(:lines?)  { line.repeat (0)} 
    root(:lines?) 
end 

puts MyParser.new.parse(""" this is a line 
so is this 

that was too 
This ends""").inspect 

जाहिर है अगर आप पार्सर से आप स्ट्रिंग के साथ प्राप्त कर सकते हैं :: विभाजन ("\ n") के साथ और अधिक करना चाहते हैं आप उपयोगी कुछ :)


मैं साथ line_body का स्थान ले लेगा इस सवाल का जवाब देने के लिए जल्दी चले गए और इसे उलझा लिया। मैं बस अपनी गलती की व्याख्या करता हूं, और आपको दिखाता हूं कि उस तरह की गलतियों से कैसे बचें।

मेरा पहला जवाब यहां है।

rule(:eol) { str('\n') | any.absent? } 
rule(:line) { (eol.absent? >> any).repeat >> eol } 
rule(:lines) { line.as(:line).repeat } 

मैं अपने सामान्य नियमों का पालन नहीं किया:

  • हमेशा दोहराने गिनती स्पष्ट
  • किसी भी नियम है कि शून्य लम्बाई तार मिलान कर सकते हैं, नाम एक में समाप्त होने वाले होना चाहिए बनाने के '?'

तो लागू इन ...

rule(:eol?) { str('\n') | any.absent? } 
# as the second option consumes nothing 

rule(:line?) { (eol.absent? >> any).repeat(0) >> eol? } 
# repeat(0) can consume nothing 

rule(:lines?) { line.as(:line?).repeat(0) } 
# We have a problem! We have a rule that can consume nothing inside a `repeat`! 

यहाँ देख कारण है कि हम एक अनंत लूप प्राप्त करने देता है। चूंकि इनपुट का उपभोग होता है, तो आप केवल end of file के साथ समाप्त होते हैं, जो eol? से मेल खाता है और इसलिए line? (जैसा कि लाइन बॉडी खाली हो सकता है)। lines 'repeat के अंदर होने के नाते, यह हमेशा के लिए कुछ भी और लूप खाने के बिना मेल खाता रहता है।

हमें लाइन नियम बदलने की जरूरत है ताकि यह हमेशा कुछ खा सके।

rule(:cr)   { str('\n') } 
rule(:eol?)  { cr | any.absent? } 
rule(:line_body) { (eol.absent? >> any).repeat(1) } 
rule(:line)  { cr | line_body >> eol? } 
rule(:lines?)  { line.as(:line).repeat(0) } 

अब line, या तो एक cr (खाली लाइनों के लिए), या कम से कम एक चरित्र वैकल्पिक eol? के बाद कुछ मेल खाना चाहिए। सभी repeat के पास ऐसे शरीर हैं जो कुछ उपभोग करते हैं। अब हम सुनहरे हैं।

+0

यह मेरे लिए एक अनंत लूप में बदल जाता है। – Danyel

+0

ओह। हाँ मैं इसे ठीक कर दूंगा। –

+0

अनंत लूप तब होते हैं जब आपके पास ऐसे नियम होते हैं जो किसी इनपुट को खपत किए बिना मिल सकते हैं। यहां 'लाइन' एक खाली रेखा से मेल खाता है, उसके बाद' eol' 'के' any.absent? 'संस्करण के बाद जो कुछ भी उपभोग नहीं करता है, इसलिए यह मिलान रख सकता है। –

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