2010-08-21 12 views
8

मेरे पास मार्कअप भाषा है जो मार्कडाउन के समान है और एसओ द्वारा उपयोग की जाने वाली एक है।मार्कडाउन जैसी भाषा के लिए पार्सर लागू करना

विरासत पार्सर रेगेक्स पर आधारित था और बनाए रखने के लिए पूरी दुःस्वप्न था, इसलिए मैं अपने स्वयं के समाधान के साथ ईबीएनएफ व्याकरण के आधार पर आया हूं और एमएक्सटीक्स्टटूल/सरलपार्स के माध्यम से लागू किया गया है।

हालांकि, कुछ टोकन के साथ समस्याएं हैं जिनमें एक-दूसरे को शामिल किया जा सकता है, और मुझे ऐसा करने का 'सही' तरीका नहीं दिख रहा है।

newline   := "\r\n"/"\n"/"\r" 
indent   := ("\r\n"/"\n"/"\r"), [ \t] 
number   := [0-9]+ 
whitespace  := [ \t]+ 
symbol_mark  := [*_>#`%] 
symbol_mark_noa := [_>#`%] 
symbol_mark_nou := [*>#`%] 
symbol_mark_nop := [*_>#`] 
punctuation  := [\(\)\,\.\!\?] 
noaccent_code := -(newline/'`')+ 
accent_code  := -(newline/'``')+ 
symbol   := -(whitespace/newline) 
text    := -newline+ 
safe_text  := -(newline/whitespace/[*_>#`]/'%%'/punctuation)+/whitespace 
link    := 'http'/'ftp', 's'?, '://', (-[ \t\r\n<>`^'"*\,\.\!\?]/([,\.\?],?-[ \t\r\n<>`^'"*]))+ 
strikedout  := -[ \t\r\n*_>#`^]+ 
ctrlw   := '^W'+ 
ctrlh   := '^H'+ 
strikeout  := (strikedout, (whitespace, strikedout)*, ctrlw)/(strikedout, ctrlh) 
strong   := ('**', (inline_nostrong/symbol), (inline_safe_nostrong/symbol_mark_noa)* , '**')/('__' , (inline_nostrong/symbol), (inline_safe_nostrong/symbol_mark_nou)*, '__') 
emphasis    := ('*',?-'*', (inline_noast/symbol), (inline_safe_noast/symbol_mark_noa)*, '*')/('_',?-'_', (inline_nound/symbol), (inline_safe_nound/symbol_mark_nou)*, '_') 
inline_code   := ('`' , noaccent_code , '`')/('``' , accent_code , '``') 
inline_spoiler  := ('%%', (inline_nospoiler/symbol), (inline_safe_nop/symbol_mark_nop)*, '%%') 
inline    := (inline_code/inline_spoiler/strikeout/strong/emphasis/link) 
inline_nostrong  := (?-('**'/'__'),(inline_code/reference/signature/inline_spoiler/strikeout/emphasis/link)) 
inline_nospoiler  := (?-'%%',(inline_code/emphasis/strikeout/emphasis/link)) 
inline_noast   := (?-'*',(inline_code/inline_spoiler/strikeout/strong/link)) 
inline_nound   := (?-'_',(inline_code/inline_spoiler/strikeout/strong/link)) 
inline_safe   := (inline_code/inline_spoiler/strikeout/strong/emphasis/link/safe_text/punctuation)+ 
inline_safe_nostrong := (?-('**'/'__'),(inline_code/inline_spoiler/strikeout/emphasis/link/safe_text/punctuation))+ 
inline_safe_noast  := (?-'*',(inline_code/inline_spoiler/strikeout/strong/link/safe_text/punctuation))+ 
inline_safe_nound  := (?-'_',(inline_code/inline_spoiler/strikeout/strong/link/safe_text/punctuation))+ 
inline_safe_nop  := (?-'%%',(inline_code/emphasis/strikeout/strong/link/safe_text/punctuation))+ 
inline_full   := (inline_code/inline_spoiler/strikeout/strong/emphasis/link/safe_text/punctuation/symbol_mark/text)+ 
line     := newline, ?-[ \t], inline_full? 
sub_cite    := whitespace?, ?-reference, '>' 
cite     := newline, whitespace?, '>', sub_cite*, inline_full? 
code     := newline, [ \t], [ \t], [ \t], [ \t], text 
block_cite   := cite+ 
block_code   := code+ 
all     := (block_cite/block_code/line/code)+ 

सबसे पहले समस्या है, स्पॉइलर, मजबूत और जोर मनमाना क्रम में एक दूसरे को शामिल कर सकते हैं:

यहाँ मेरी व्याकरण का हिस्सा है। और यह संभव है कि बाद में मुझे ऐसे इनलाइन मार्कअप की आवश्यकता होगी।

मेरे वर्तमान समाधान में प्रत्येक संयोजन (inline_noast, inline_nostrong, आदि) के लिए अलग टोकन बनाना शामिल है, लेकिन जाहिर है, ऐसे संयोजनों की संख्या मार्कअप तत्वों की बढ़ती संख्या के साथ बहुत तेजी से बढ़ती है।

दूसरी समस्या यह है कि मजबूत/जोर से इन लुकहेड व्यवहार __._.__*__.__...___._.____.__**___*** (यादृच्छिक रूप से चिह्नित मार्कअप प्रतीकों) के खराब मार्कअप के कुछ मामलों पर बहुत खराब हैं। ऐसे यादृच्छिक पाठ के कुछ केबी को पार्स करने में कुछ मिनट लगते हैं।

क्या यह मेरे व्याकरण के साथ कुछ गलत है या मुझे इस कार्य के लिए किसी अन्य प्रकार के पार्सर का उपयोग करना चाहिए?

+5

[क्लीटस] (http://stackoverflow.com/users/18393/cletus) में मार्कडाउन [अपने ब्लॉग पर] पार्सिंग पर अपने काम का वर्णन करने वाली एक लंबी श्रृंखला है (http://www.cforcoding.com/search/लेबल/markdown)। उनके पास "मार्कडाउन, ब्लॉक पार्सिंग और द रोड टू नर्क" जैसे खिताब हैं। आपको कुछ प्रासंगिक जानकारी या अंतर्दृष्टि मिल सकती है। –

+0

[PyParsing] पर एक नज़र डालें (http://pyparsing.wikispaces.com/) – leoluk

+0

@ ग्रेग थैट्स दिलचस्प, साझा करने के लिए धन्यवाद। हालांकि ऐसा लगता है कि उन्होंने इनलाइन मार्कअप को हल नहीं किया है, और मुझे ब्लॉक मार्कअप के साथ कोई समस्या नहीं है। –

उत्तर

6

यदि एक चीज़ में कोई और शामिल है, तो आम तौर पर आप उन्हें अलग टोकन के रूप में देखते हैं और फिर उन्हें व्याकरण में घोंसला देते हैं। Lepl (http://www.acooke.org/lepl जो मैंने लिखा था) और पायपार्सिंग (जो शायद सबसे लोकप्रिय शुद्ध-पायथन पार्सर है) दोनों आपको चीजों को घूमने की अनुमति देते हैं।

तो Lepl में आप की तरह कोड कुछ लिख सकते हैं:

# these are tokens (defined as regexps) 
stg_marker = Token(r'\*\*') 
emp_marker = Token(r'\*') # tokens are longest match, so strong is preferred if possible 
spo_marker = Token(r'%%') 
.... 
# grammar rules combine tokens 
contents = Delayed() # this will be defined later and lets us recurse 
strong = stg_marker + contents + stg_marker 
emphasis = emp_marker + contents + emp_marker 
spoiler = spo_marker + contents + spo_marker 
other_stuff = ..... 
contents += strong | emphasis | spoiler | other_stuff # this defines contents recursively 

तो फिर तुम देख सकते हैं, मुझे आशा है कि, कैसे सामग्री मजबूत, जोर का नेस्ट उपयोग से मेल खाएगी, आदि

वहाँ की तुलना में बहुत अधिक है यह आपके अंतिम समाधान के लिए करने के लिए है, और दक्षता किसी भी शुद्ध-पायथन पार्सर में एक मुद्दा हो सकता है (कुछ पार्सर हैं जो सी में लागू होते हैं लेकिन पाइथन से कॉल करने योग्य होते हैं। ये तेज़ होंगे, लेकिन उपयोग करने के लिए मुश्किल हो सकते हैं; मैं ' टी किसी की भी सिफारिश नहीं है क्योंकि मैंने उनका उपयोग नहीं किया है)।

+0

इसी तरह के समाधान के लिए http://stackoverflow.com/questions/3495019/parsing-latex-like-language-in-java देखें। –

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