2010-08-21 10 views
8

Markalama diline benzer bir işaretleme diline ve SO tarafından kullanılana benzer.Markdown benzeri dil için ayrıştırıcı uygulama

Eski ayrıştırıcı düzenli ifadelere dayanıyordu ve bakımı tam bir kabusdu, bu yüzden EBNF dilbilgisine dayanan kendi çözümümle geldim ve mxTextTools/SimpleParse aracılığıyla gerçekleştirdim.

Ancak birbirlerini içerebilir birkaç jeton sorunları vardır ve bunu yapmak için bir 'doğru' yol göremiyorum.

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)+ 

İlk sorundur, rüzgarlık, güçlü ve keyfi için birbirleriyle içerebilir vurgu: Burada

benim dilbilgisi parçasıdır. Ve daha sonra bu tür satır içi işaretlemeye daha fazla ihtiyacım var.

Şu anki çözümüm, her bir kombinasyon için (inline_noast, inline_nostrong, vb.) Yalnızca ayrı belirteci oluşturmayı içerir, ancak açıkçası, bu tür kombinasyonların sayısı, artan sayıda işaretleme öğesiyle çok hızlı büyür. İkinci problem, güçlü/vurgulu bu görünümlerin, __._.__*__.__...___._.____.__**___*** (rastgele yerleştirilmiş işaretleme sembolleri) gibi bazı kötü işaretlemeler üzerinde çok kötü davrandıklarıdır. Bu tür rastgele metinlerin birkaç kb'sini ayrıştırmak için dakikalar gerekir.

benim dilbilgisi ya da ben bu görev için ayrıştırıcı başka türde kullanmalıdır bir şey mi? olaylar birbirini içerir

+5

[cletus] (http://stackoverflow.com/users/18393/cletus) [blogunda] Markdown ayrıştırma konulu çalışmasını açıklayan mesajların uzun dizi (sahiptir http://www.cforcoding.com/search/etiket/markdown). "Markdown, Blok Ayrıştırma ve Cehenneme Giden Yol" gibi başlıklar var. Orada bazı alakalı bilgiler veya bilgiler bulabilirsiniz. –

+0

[PyParsing] 'e bakabilirsiniz (http://pyparsing.wikispaces.com/) – leoluk

+0

@Greg Bu ilginç, paylaştığınız için teşekkürler. Ancak, satır içi biçimlendirmeyi de çözmedi gibi görünüyor ve blok biçimleme ile ilgili hiçbir sorunum yok. –

cevap

6

, o zaman normalde ayrı simgeleri olarak onları tedavi ve dilbilgisi sonra yuva onları. Lepl (yazdığım http://www.acooke.org/lepl) ve PyParsing (muhtemelen en popüler saf Python ayrıştırıcısıdır) her ikisini de yinelemeli olarak iç içe geçirmenize izin verir.

Böylece gibi kod şey yazabilirsiniz Lepl içinde: vb Sonra

# 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 

ben içeriği kuvvetli, vurgu iç içe kullanılmasını maç olacak, nasıl umut görebilirsiniz

çok daha fazlası var Bu sizin nihai çözümünüz için yapmanız ve verimliliğin herhangi bir saf-Python ayrıştırıcısında bir sorun olabilir (C içinde uygulanan ancak Python'dan alınabilen bazı ayrıştırıcılar vardır. Bunlar daha hızlı olacaktır, ancak kullanması daha zor olabilir; Bunları kullanmadığınız için tavsiye ederim.

+0

Benzer bir çözüm için http://stackoverflow.com/questions/3495019/parsing-latex-like-language-in-java adresine bakın. –

İlgili konular