我有类似于markdown的标记语言和SO使用的标记语言。在
遗留解析器基于regex,维护起来简直是噩梦,所以我基于EBNF语法提出了自己的解决方案,并通过mxTextTools/SimpleParse实现。在
不过,有些代币可能会相互包含,但我认为没有一种“正确”的方式来实现这一点。在
以下是我语法的一部分:
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等)创建单独的令牌,但显然,随着标记元素数量的增加,这种组合的数量增长过快。在
第二个问题是,这些强/强调中的lookahead在某些错误标记的情况下表现非常差,比如__._.__*__.__...___._.____.__**___***
(大量随机放置的标记符号)。解析这种随机文本需要几分钟的时间。在
是我的语法出了什么问题,还是应该使用其他类型的解析器来完成这项任务?在
如果一个事物包含另一个事物,那么通常您将它们作为单独的标记处理,然后将它们嵌套在语法中。Lepl(http://www.acooke.org/lepl)和PyParsing(可能是最流行的纯Python解析器)都允许递归地嵌套东西。在
所以在Lepl中,您可以编写类似以下内容的代码:
然后您可以看到,我希望,内容将如何匹配强、强调等嵌套用法
对于您的最终解决方案,还有很多工作要做,效率在任何纯Python解析器中都可能是一个问题(有些解析器是用C实现的,但可以从Python调用)。这些会更快,但可能更难使用;我不能推荐任何一个,因为我没有使用过它们)。在
相关问题 更多 >
编程相关推荐