Scala,树结构数据的解析器组合器

标签 scala parser-combinators

如何使用解析器来解析跨越多行的记录?我需要解析树数据(并最终将其转换为树数据结构)。我在下面的代码中遇到了一个难以追踪的解析错误,但不清楚这是否是 Scala 解析器的最佳方法。问题实际上更多是关于解决问题的方法,而不是调试现有代码。

EBNF-ish 语法是:

SP          = " "
CRLF        = "\r\n"
level       = "0" | "1" | "2" | "3"
varName     = {alphanum}
varValue    = {alphnum}
recordBegin = "0", varName
recordItem  = level, varName, [varValue]
record      = recordBegin, {recordItem}
file        = {record}

尝试实现和测试语法:
import util.parsing.combinator._
val input = """0 fruit
1 id 2
1 name apple
2 type red
3 size large
3 origin Texas, US
2 date 2 aug 2011
0 fruit
1 id 3
1 name apple
2 type green
3 size small
3 origin Florida, US
2 date 3 Aug 2011"""

object TreeParser extends JavaTokenParsers {
  override val skipWhitespace = false
  def CRLF = "\r\n" | "\n"
  def BOF = "\\A".r
  def EOF = "\\Z".r
  def TXT = "[^\r\n]*".r
  def TXTNOSP = "[^ \r\n]*".r
  def SP = "\\s".r
  def level: Parser[Int] = "[0-3]{1}".r ^^ {v => v.toInt}
  def varName: Parser[String] = SP ~> TXTNOSP
  def varValue: Parser[String] = SP ~> TXT
  def recordBegin: Parser[Any] =  "0" ~ SP ~ varName ~ CRLF
  def recordItem: Parser[(Int,String,String)] = level ~ varValue ~ opt(varValue) <~ CRLF ^^
    {case l ~ f ~ v => (l,f,v.map(_+"").getOrElse(""))}
  def record: Parser[List[(Int,String,String)]] = recordBegin ~> rep(recordItem)
  def file: Parser[List[List[(Int,String,String)]]] = rep(record) <~ EOF
  def parse(input: String) = parseAll(file, input)
}

val result = TreeParser.parse(input).get
result.foreach(println)

最佳答案

显式处理空格并不是一个特别好的主意。而且,当然,使用 get意味着您会丢失错误消息。在这个特定的例子中:

[1.3] failure: string matching regex `\s' expected but `f' found

0 fruit

  ^

这实际上很清楚,尽管问题是为什么它需要一个空间。现在,这显然是在处理 recordBegin规则,其定义如下:
"0" ~ SP ~ varName ~ CRLF

所以,它解析零,然后是空格,然后是 fruit必须针对 varName 进行解析.现在,varName定义如下:
SP ~> TXTNOSP

另一个空间!所以,fruit应该以空格开头。

关于Scala,树结构数据的解析器组合器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6180617/

相关文章:

scala - 解析器组合器未终止 - 如何记录正在发生的事情?

rust - 使用 nom 捕获整个连续的匹配输入

scala - 如何使用 Scala 解析器组合器处理不区分大小写的关键字

compiler-construction - Scalas/Haskells 解析器组合器是否足够?

scala - 读取多个AVRO文件时对象无法序列化错误

scala - 为什么 Unit 不在 Scala 中扩展 Product?

rust - 使用 nom 从输入中识别 float

scala - Spark 聚合计数条件

scala - 为只有一个字段的案例类派生类型类实例

scala - 为什么重载具有不同上限的多态方法不能在 Scala 中编译