解析嵌套括号内包含的值

Jac*_*ack 3 parsing scala

我只是愚弄,奇怪地发现在一个简单的递归函数中解析嵌套括号有点棘手.

例如,如果该计划的目的是查找用户的详细信息,它可能会从{{name surname} age}{Bob Builder age}再到Bob Builder 20.

这是一个迷你程序,用于对大括号中的总计进行求和,以演示该概念.

  // Parses string recursively by eliminating brackets
  def parse(s: String): String = {
    if (!s.contains("{")) s
    else {
      parse(resolvePair(s))
    }
  }

  // Sums one pair and returns the string, starting at deepest nested pair
  // e.g.
  // {2+10} lollies and {3+{4+5}} peanuts
  // should return:
  // {2+10} lollies and {3+9} peanuts
  def resolvePair(s: String): String = {
    ??? // Replace the deepest nested pair with it's sumString result
  }

  // Sums values in a string, returning the result as a string
  // e.g. sumString("3+8") returns "11"
  def sumString(s: String): String = {
    val v = s.split("\\+")
    v.foldLeft(0)(_.toInt + _.toInt).toString
  }

  // Should return "12 lollies and 12 peanuts"
  parse("{2+10} lollies and {3+{4+5}} peanuts")
Run Code Online (Sandbox Code Playgroud)

任何可以取代它的代码的想法???都会很棒.这主要是出于好奇,我正在寻找这个问题的优雅解决方案.

huy*_*hjl 6

解析器组合器可以处理这种情况:

import scala.util.parsing.combinator.RegexParsers
object BraceParser extends RegexParsers {
  override def skipWhitespace = false
  def number = """\d+""".r ^^ { _.toInt }
  def sum: Parser[Int] = "{" ~> (number | sum) ~ "+" ~ (number | sum) <~ "}" ^^ {
    case x ~ "+" ~ y => x + y
  }
  def text = """[^{}]+""".r
  def chunk = sum ^^ {_.toString } | text
  def chunks = rep1(chunk) ^^ {_.mkString} | ""
  def apply(input: String): String = parseAll(chunks, input) match {
    case Success(result, _) => result
    case failure: NoSuccess => scala.sys.error(failure.msg)
  }
}
Run Code Online (Sandbox Code Playgroud)

然后:

BraceParser("{2+10} lollies and {3+{4+5}} peanuts")
//> res0: String = 12 lollies and 12 peanuts
Run Code Online (Sandbox Code Playgroud)

在熟悉解析器组合器之前有一些投资,但我认为这是值得的.

为了帮助您破译上面的语法:

  • 正则表达式和字符串具有隐式转换以创建具有字符串结果的原始解析器,它们具有类型Parser[String].
  • ^^运营商允许的功能应用到解析的元素
    • 它可以转换Parser[String]Parser[Int]^^ {_.toInt}
    • 解析器是一个monad,Parser[T].^^(f)相当于Parser[T].map(f)
  • ~,~>并且<~需要一些输入为以一定的顺序
    • ~><~输入的一侧退出的结果的
    • case a ~ b允许模式相匹配的结果
    • 解析器是一个monad,(p ~ q) ^^ { case a ~ b => f(a, b) }相当于for (a <- p; b <- q) yield (f(a, b))
    • (p <~ q) ^^ f 相当于 for (a <- p; _ <- q) yield f(a)
  • rep1 是一个或多个元素的重复
  • | 尝试将输入与其左侧的解析器匹配,如果失败,则会尝试右侧的解析器