我一直在尝试编写一个解析器,用于解析一种(非常)简单的语言。该语言如下所示:
block{you are a cow too blkA{ but maybe not} and so is he} hear me moo blockZ{moooooo}
我可以使用正则表达式将其拆分开:
.*?[^ ]*?\\{
.*?\\}
这段代码会一直读取字符直到找到匹配的 [^ ]*?\\{
或者 \\}
,也就是一个块的开头或结尾。我的问题是,如果我想使用Scala的解析组合器来实现,该怎么做呢?我目前有如下代码:
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)+
I get:
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)
这种做法在某种程度上是正确的。不过它是逐个解析非块字符,可能存在性能问题(我想?)。有没有一种方法可以一次解析所有这些非块字符,并将它们保留在一个大字符串中?