解析器将String转换为Any类型

时间:2013-12-27 14:16:33

标签: scala parser-combinators

我有以下简单的解析器(实际上它有点复杂,但这个简单的例子说明问题是一样的)。

我有第一个匹配name的解析器,String由于某种原因而被转换为Any类型。此外,第二个2列表是可选的,因此它们可能存在或者它们不存在。但是在我的域对象中,如果它们不是,它们各自的集合将是空的。

我似乎无法理解第一个问题。出于某种原因,当我删除第一个<~时,名称再次成为String,剩下的唯一错误是带有可选列表的错误,我认为我可以通过匹配Option实例,虽然我将拥有相当多的这些可选列表,但我不想要它们的所有排列,包括Some和None。

最佳方法是什么?

import scala.util.parsing.combinator.RegexParsers

case class Test(name: String, extensions : Set[String] = Set[String](), 
                objects : Set[String] = Set[String]())

object TestParser extends RegexParsers {
  def test = "((:name" ~> name <~ ")" ~ (extensions_def?) ~ (objects_def?) <~ ")" ^^ {
      case name ~ extensions_def ~ objects_def =>
        Test(name, extensions_def, objects_def)
    }

  def name : Parser[String] = """[a-zA-Z][a-zA-Z0-9_-]*""".r

  def extensions_def = "(:extensions" ~> (extensions_key+) <~ ")"
  def extensions_key = ":funcs" | ":literals" | ":numbers"

  def objects_def = "(:objects" ~> (name+) <~ ")"

  def main(args: Array[String]) {

    val s = "(test hello (:extensions :funcs :numbers) (:objects obj1 obj2 obj3))"

    val res = parseAll(test, s)
    res match {
      case Success(r, n) => println(r)
      case Failure(msg, n) => println(msg)
      case Error(msg, n) => println(msg)
    }
  }
}

1 个答案:

答案 0 :(得分:1)

您必须在括号内对"(:name" ~> name <~ ")"进行分组(或者您可以像name_defextensions_def那样定义objects_def。至于匹配None/Some排列,可能更容易匹配选项并定义optionListToSet方法,如下所示:

import scala.util.parsing.combinator.RegexParsers

case class Test(name: String, extensions : Set[String] = Set[String](), 
  objects : Set[String] = Set[String]())

object TestParser extends RegexParsers {
  def test = "(" ~> ("(:name" ~> name <~ ")") ~ (extensions_def?) ~ (objects_def?) <~ ")" ^^ {
    case name ~ extensions_def ~ objects_def =>
      Test(name, optionListToSet(extensions_def), optionListToSet(objects_def))
  }

  def optionListToSet[A](o:Option[List[A]]) = o.map(_.toSet).getOrElse(Set[A]())

  def name : Parser[String] = """[a-zA-Z][a-zA-Z0-9_-]*""".r

  def extensions_def = "(:extensions" ~> (extensions_key+) <~ ")"
  def extensions_key = ":funcs" | ":literals" | ":numbers"

  def objects_def = "(:objects" ~> (name+) <~ ")"

  def main(args: Array[String]) {

    val s1 = "((:name test) (:extensions :funcs :numbers) (:objects obj1 obj2 obj3))"
    val res1 = parseAll(test, s1)
    res1 match {
      case Success(r, n) => println(r)
      case Failure(msg, n) => println(msg)
      case Error(msg, n) => println(msg)
    }

    val s2 = "((:name test) (:objects obj1 obj2 obj3))"
    val res2 = parseAll(test, s2)
    res2 match {
      case Success(r, n) => println(r)
      case Failure(msg, n) => println(msg)
      case Error(msg, n) => println(msg)
    }
  }
}

Output :

Test(test,Set(:funcs, :numbers),Set(obj1, obj2, obj3))

Test(test,Set(),Set(obj1, obj2, obj3))