使用scala StandardTokenParser解析分隔的多行字符串

时间:2014-07-14 23:02:57

标签: scala parsing

我发现了一些类似的问题,但似乎并没有直接解决我的需求。

我正在使用Scala创建一个DSL,并且已经定义了很多。但是,部分语言需要处理多行文本文档的块,这些文档由解析器作为单独的实体收集和处理。我想以某种方式划分这些块(例如{{}}之类的内容),只收集分隔符之间的所有内容并将其作为DocString返回(case我的解析器中的类)。然后,这些块将用于创建其他最终用户文档以及其他已解析文件。

解析器已经构建为StandardTokenParsers派生类。我想我可以将它转换为RegexParsers派生类,只使用正则表达式,但这将是一个重大变化,我的语法很多都必须重新编写。我不确定这样做是否有任何好处(除了支持所需的文档块)。

我看过Using regex in StandardTokenParsers并找到了this。我不确定其中任何一个是否会实际处理我需要的东西,或者如果他们这样做的话如何开始。

如果有人对可行的方法有任何想法,我会很感激。

作为一个例子,这是我尝试过的(来自Using regex in StandardTokenParsers):

object DModelParser extends StandardTokenParsers {
    ...
    def modelElement: Parser[ModelElement] =
        (other stuff, not important here) | docBlock

    import scala.util.matching.Regex
    import lexical.StringLit

    def regexBlockMatch(r: Regex): Parser[String] = acceptMatch(
        "string block matching regex " + r,
        {case StringLit(s) if r.unapplySeq(s).isDefined => s})

    val bmr = """\{\{((?s).*)\}\}""".r

    def docBlockStr: Parser[String] = regexBlockMatch(bmr)
    def docBlock: Parser[DocString] = 
      docBlockStr ^^ { s => new DocString(s) }
    ...
}

但是,当传递它时,如下所示:

{{ A block of docs }}

它无法匹配导致解析器停止解析。我认为在这种情况下问题出现在case StringLit(s)但我不确定。

修改

行。 StringLit 是个问题。我忘了这只会匹配双引号中的字符串。所以我尝试用以下代码替换上面的字符串:

"{{ A block of docs }}"

它工作正常。但是,多线问题仍然存在。如果我将其替换为:

"{{ A block 
 of docs }}"

然后它仍然无法解析。同样,我认为StringLit不适用于换行符。

修改

我遇到了另一种选择,但我不确定如何让它在解析器中运行。如果我可以读取和匹配仅包含开头分隔符的行,则收集到List[String]所有行,直到只包含足够的结束分隔符的行。有没有办法做到这一点?

编辑2015年6月22日

我走了一个不同的方向,这似乎适用于我迄今为止尝试过的例子:

 // https://stackoverflow.com/questions/24771341/scala-regex-multiline-match-with-negative-lookahead
 def docBlockRE = regex("""(?s).*?(?=}})""".r)
 def docBlock: Parser[DocString] =
     "{{" ~> docBlockRE <~ "}}" ^^ { case str => new DocString(str) }

0 个答案:

没有答案