【问题标题】:SCALA: How to convert a Parser Combinator result to Scala List[String]?SCALA:如何将 Parser Combinator 结果转换为 Scala List[String]?
【发布时间】:2016-08-05 16:50:54
【问题描述】:

我正在尝试为与 Milner 的 CCS 非常相似的语言编写解析器。到目前为止,我所解析的基本上是以下类型的表达式:

  • a.b.a.1
  • a.0

表达式必须以字母开头(不包括 t),并且在第一个字母之后可以有任意数量的字母(用“.”分隔)。表达式必须以数字结尾(为简单起见,我现在选择了 0 到 2 之间的数字)。我想为 Scala 使用 Parser Combinators,但这是我第一次使用它们。这是我目前所拥有的:

import scala.util.parsing.combinator._

class SimpleParser extends RegexParsers {
  def alpha: Parser[String] = """[^t]{1}""".r ^^ { _.toString }
  def digit: Parser[Int] = """[0-2]{1}""".r ^^ { _.toInt }

  def expr: Parser[Any] = alpha ~ "." ~ digit ^^ {
    case al ~ "." ~ di => List(al, di)
  }

  def simpleExpression: Parser[Any] = alpha ~ "." ~ rep(alpha ~ ".") ~ digit //^^ {  }
}

正如您在def expr :Parser[Any] 中看到的那样,我试图将结果作为列表返回,因为 Scala 中的列表非常易于使用(在我看来)。这是如何将 Parser[Any] 结果转换为列表的正确方法吗?谁能给我任何提示,告诉我如何为def simpleExpression:Parser[Any] 做到这一点。

我想使用列表的主要原因是因为在解析和表达式之后我希望能够使用它。例如,给定表达式 a.b.1,如果给定一个 'a',我想使用该表达式以得到一个新表达式: b.1(即 a.b.1 ->(a)-> b.1)。这背后的想法是模拟有限状态自动机。任何关于如何改进我的实施的提示都值得赞赏。

【问题讨论】:

    标签: scala parsing parser-combinators


    【解决方案1】:

    为了保证类型安全,我推荐一个解析器,它产生一个字符串列表和一个 int 的元组。也就是说,输入a.b.a.1 将被解析为(List("a", "b", "a"), 1)。另请注意,alpha 的正则表达式已修改为排除任何非小写字母(除了 t)。

    class SimpleParser extends RegexParsers {
      def alpha: Parser[String] = """[a-su-z]{1}""".r ^^ { _.toString }
      def digit: Parser[Int] = """[0-2]{1}""".r ^^ { _.toInt }
    
      def repAlpha: Parser[List[String]] = rep1sep(alpha, ".")
    
      def expr: Parser[(List[String], Int)] = repAlpha ~ "." ~ digit ^^ {
        case alphas ~ _ ~ num =>
          (alphas, num)
      }
    }
    

    使用 SimpleParser 的一个实例,这是我得到的输出:

    println(parser.parse(parser.expr, "a.b.a.1"))
    // [1.8] parsed: (List(a, b, a),1)
    
    println(parser.parse(parser.expr, "a.0"))
    // [1.4] parsed: (List(a),0)
    

    【讨论】:

    • 非常感谢。那么,您将如何进行模式匹配元组中的列表呢?和列表的普通模式匹配一​​样吗?
    • 我成功了。我所做的如下:def consume(c: String, t: (List[String],Int)):(List[String],Int)= { t._1 match { case Nil => (List(),t._2) case x::xs => if (x.equalsIgnoreCase(c)) (xs,t._2) else (x::xs,t._2) } }
    猜你喜欢
    • 2020-01-11
    • 2015-10-09
    • 2016-08-22
    • 2019-09-10
    • 2020-05-21
    • 2016-07-21
    • 1970-01-01
    • 2018-02-20
    • 1970-01-01
    相关资源
    最近更新 更多