我一直在尝试为一种(非常)简单的语言制作一个解析器,如下所示:
block{you are a cow too blkA{ but maybe not} and so is he} hear me moo blockZ{moooooo}
我可以使用正则表达式将其分开:
.*?[^ ]*?\\{
.*?\\}
这基本上会一直吃字符,直到它找到匹配的东西 [^ ]*?\\{
或\\}
:块的开始或结束。我的问题是,如果我想使用 Scala 的 Parser Combinators 来做到这一点,我该怎么做?我目前有:
def expr: Parser[Any] = (block | text)+
def text = ".+?".r
def block = "[^ ]*?\\{".r ~ expr ~ "}"
但这不起作用:
parsed: List(b, l, o, c, k, {, y, o, u, a, r, e, a, c, o, w, t, o, o, b, l, k, A, {, b, u, t, m, a, y, b, e, n, o, t, }, a, n, d, s, o, i, s, h, e, }, h, e, a, r, m, e, m, o, o)
似乎block
解析器没有触发,因此text
解析器被反复触发。但是当我删除text
解析器时:
def expr: Parser[Any] = (block)+
我得到:
failure: string matching regex `[^ ]*?\{' expected but `y' found
block{you are a cow too blkA{ but maybe not} and so is he} hear me moo
^
所以很明显block
解析器确实有效,除非当text
解析器存在时。发生了什么?对于如此基本的语法,是否有一种“正确”的方式来做到这一点?
编辑:更改了标题,因为与其说是不情愿,不如说是解决问题
编辑:我现在有这个:
def expr: Parser[Any] = (block | text)+
def text = "[^\\}]".r
def block = "[^ ]*?\\{".r ~ expr ~ "}"
这背后的逻辑是,对于每个字符,它都会测试它是否是一个块的开始。如果不是,它会移动到下一个字符。这给了我:
parsed: List(((block{~List(y, o, u, a, r, e, a, c, o, w, t, o, o, ((blkA{~List(b, u, t, m, a, y, b, e, n, o, t))~}), a, n, d, s, o, i, s, h, e))~}), h, e, a, r, m, e, m, o, o)
这是正确的。它正在逐一解析非块字符,这可能是一个性能问题(我认为?)。有没有办法一次解析所有这些非块字符并将它们留在一个大字符串中?