【问题标题】:Parser combinator for enumerated values枚举值的解析器组合器
【发布时间】:2013-07-02 03:13:15
【问题描述】:

有没有更简洁的方法将字符串映射到解析器组合器中的枚举值?

object Mode extends Enumeration {
  type Mode = Value
  val View, Add, Modify, Delete  = Value
}

import Mode._

object ModeParser extends JavaTokenParsers {
  def mode: Parser[Mode] = ("^(" + Mode.values.mkString("|") + ")$").r ^^ { 
    Mode.withName(_) 
  }
}

【问题讨论】:

    标签: scala parser-combinators


    【解决方案1】:

    解析器是可组合的,因此只要您可以构建一个解析器来读取Mode.Value,您就可以使用| 组合所有此类变体:

    object ModeParser extends JavaTokenParsers {
      val mode: Parser[Mode.Value] = Mode.values.toList map{m =>
        literal(m.toString) ^^^ m
      } reduceLeft {_ | _}
    }
    

    你会这样使用它:

    scala> ModeParser.parseAll(ModeParser.mode, "Viewx")
    

    【讨论】:

    • 我试图尝试使用 reduceLeft 解决方案,但找不到。谢谢,我试试看!
    • literal(m.toString) 允许 "Viewx" 和 "xView" 成功解析。将其更改为使用 phrase(m.toString) 可以解决此问题。
    • 我假设您会将其用作ModeParser.parseAll(ModeParser.mode, "Viewx"),就像@senia 的答案所暗示的那样
    • 我想先单独测试它,然后将它与其他解析器结合起来。我发现当我使用mode ~ anotherParser 时,我必须改用literal。因此,我通过使用您的解决方案定义 modeLiteral 解析器来支持这两种用法,并将我的解析器更改为调用 phrase(modeLiteral)。
    【解决方案2】:

    您可以使用^? 方法将ident 解析器转换为mode 解析器:

    object ModeParser extends JavaTokenParsers {
      val modes = Mode.values.map{v => v.toString -> v}.toMap
      def mode: Parser[Mode.Value] = ident ^? ( 
        { case s if modes.contains(s) => modes(s) },
        s => s"Mode expected, but '$s' found."
      )
    }
    

    用法:

    scala> ModeParser.parseAll(ModeParser.mode, "Modify")
    res0: ModeParser.ParseResult[Mode.Value] = [1.7] parsed: Modify
    
    scala> ModeParser.parseAll(ModeParser.mode, "modify")
    res1: ModeParser.ParseResult[Mode.Value] =
    [1.7] failure: Mode expected, but 'modify' found.
    
    modify
          ^
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-01
      • 1970-01-01
      • 2012-06-26
      • 1970-01-01
      • 2015-09-23
      • 1970-01-01
      • 2014-01-04
      相关资源
      最近更新 更多