我有一个项目,它仍然处于萌芽状态,我正在尝试使用真正的语法编写 wiki 解析器。我发现了一个似乎相当完整的克里奥尔语语法,并由第三方确认可以工作(使用 ANTLR)。
我已经开始将事情向前推进,但是遇到了一些障碍,我假设这些障碍是 pyparsing 的常见绊脚石。
escaped
: ESCAPE STAR STAR
| ESCAPE .
// '.' in a parser rule means arbitrary token, not character
;
我想出的是:
ESCAPE = Literal('~')
STAR = Literal('*')
escaped = ESCAPE + STAR + STAR | ESCAPE + Word(printables, max=1)
我在 pyparsing 中找不到任何其他内容来匹配单个字符,但这似乎可行。但是,在查看标题内容时,我有这个子表达式:
heading_content
: heading_markup heading_content ( heading_markup )?
| ( ~( EQUAL | ESCAPE | NEWLINE | EOF ) | escaped )+
;
我正在使用前锋,但对于第二部分,我最终得到:
OneOrMore(CharsNotIn("=~\r\n") | escaped)('heading_content')
现在这匹配“test”和“test~=”,但不匹配“test~=foo”,它只匹配“test”部分。这是为什么?
其次,我想知道除了 CharsNotIn 是否还有其他方法来指定内容部分?
现在真正让我难过的是试图匹配未格式化的文本部分。这是匹配各种纯文本的核心。现在语法指定:
text_unformatted
: ( ~( ITAL
| STAR
| LINK_OPEN
| IMAGE_OPEN
| NOWIKI_OPEN
| EXTENSION
| FORCED_LINEBREAK
| ESCAPE
| NEWLINE
| EOF )
| forced_linebreak
| escaped )+
这是我碰壁的地方。现在上面的简单位定义为:
# STAR, ESCAPE and escaped defined above
ITAL = Literal('//')
LINK_OPEN = Literal('[[')
IMAGE_OPEN = Literal('{{')
NOWIKI_OPEN = Literal('{{{')
EXTENSION = Literal('@@')
FORCED_LINEBREAK = Literal(r'\\')
CR = Literal('\r')
LF = Literal('\n')
NEWLINE = Optional(CR) + LF | CR
然而,我的 OneOrMore(NotAny(...) | FORCED_LINEBREAK | escaped) 的幼稚方法不起作用,最终无限循环。多读一点文档表明 NotAny 实际上并没有返回任何匹配项。那么我们如何匹配这个呢?我不能使用 CharNotIn(...) 因为单个 '{' 是完全有效的。
指针表示赞赏。