scala解析器:知道如何处理地图,但不知道如何处理地图列表

时间:2014-05-24 12:52:41

标签: scala parsing

使用以下代码,我可以将地图中的键值与值进行比较。 例如,“column1> 2”将比较map(“column1”)> 2,并且结果为true或false,基于地图。但是如何处理这样的地图列表呢?我在数据库中有一个表,所以我将得到一个行列表,每行可以表示为一个映射,然后我需要处理每一行,并打印该行是否匹配条件。我知道可以很容易地在sql中完成,但我想知道如何在scala中完成。

package test

import scala.util.parsing.combinator.syntactical._

object BookParse extends StandardTokenParsers {
  val lookup=Map[String,Double]("column1"->1,"column2"->2)
  lexical.delimiters ++= List(">","<",">=","!=","<>","<=","=")
  def value[double] = numericLit ^^ { s => s.toDouble }
  def columnValue[double]=ident ^^ {s=>lookup(s)}
  def condition=(columnValue|value)~(">"|"<"|"<="|">="|"<>"|"!="|"=")~(columnValue|value) ^^ {
    case left ~x ~ right=>{
      x match {
        case ">" =>if (left > right) println("true") else println("false")
        case "<" =>if (left < right) println("true") else println("false")
        case "<>"=>if (left != right) println("true") else println("false")
        case "!="=>if (left != right) println("true") else println("false")
        case ">="=>if (left >= right) println("true") else println("false")
        case "<="=>if (left <= right) println("true") else println("false")
        case "="=> if (left == right) println("true") else println("false")
      }
    }
  }

  def parse(s: String) = {
    val tokens = new lexical.Scanner(s)
    phrase(condition)(tokens)
  }

  def test(extrString: String) = {
    parse(extrString) match {
      case Success(_,_) => println("done")
      case Failure(msg, _) => println("Failure: " + msg)
       case Error(msg, _) => println("Error: " + msg)
    }
  }

  def main(args: Array[String]) {
    test("column1 > 2")
  }
}

1 个答案:

答案 0 :(得分:1)

一个稍微好一点的方法就是让解析器返回&#34;表达式&#34;可以在地图的上下文中评估(而不是依赖于解析器内的副作用)。

import scala.util.parsing.combinator.syntactical._

object BookParse extends StandardTokenParsers {
  lexical.delimiters ++= List(">", "<", ">=", "!=", "<>", "<=", "=")

  val value: Parser[Map[String, Double] => Double] =
    numericLit ^^ (v => _ => v.toDouble)

  val columnValue: Parser[Map[String, Double] => Double] =
    ident ^^ (name => env => env(name))

  val condition: Parser[Map[String, Double] => Boolean] =
    (columnValue | value) ~
    (">" | "<" | "<=" | ">=" | "<>" | "!=" | "=") ~
    (columnValue | value) ^^ {
      case left ~ ">"  ~ right => env => left(env) >  right(env)
      case left ~ "<"  ~ right => env => left(env) <  right(env)
      case left ~ "<>" ~ right => env => left(env) != right(env)
      case left ~ "!=" ~ right => env => left(env) != right(env)
      case left ~ ">=" ~ right => env => left(env) >= right(env)
      case left ~ "<=" ~ right => env => left(env) <= right(env)
      case left ~ "="  ~ right => env => left(env) == right(env)
    }

  def parse(s: String) = {
    val tokens = new lexical.Scanner(s)
    phrase(condition)(tokens)
  }
}

现在,如果您有一些示例数据:

val rows: List[Map[String, Double]] = List(
  Map("column1" -> 1, "column2" -> 2),
  Map("column1" -> 3, "column2" -> 3)
)

您可以写下以下内容:

scala> val myCond = BookParse.parse("column1 > 2").get
myCond: Map[String,Double] => Boolean = <function1>

scala> rows.filter(myCond)
res0: List[Map[String,Double]] = List(Map(column1 -> 3.0))

(请注意,有几种方法可以改善错误处理。)