我只是在愚弄,奇怪地发现在一个简单的递归函数中解析嵌套括号有点棘手。
例如,如果程序的目的是查找用户详细信息,则可能会从{{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")
任何可以取代???
的清晰代码的想法都会很棒。这主要是出于好奇,我正在寻找这个问题的优雅解决方案。
答案 0 :(得分:6)
Parser组合器可以处理这种情况:
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)
}
}
然后:
BraceParser("{2+10} lollies and {3+{4+5}} peanuts")
//> res0: String = 12 lollies and 12 peanuts
在熟悉解析器组合器之前有一些投资,但我认为这是值得的。
帮助您破译上述语法:
Parser[String]
。^^
运算符允许将函数应用于已解析的元素
Parser[String]
Parser[Int]
转换为^^ {_.toInt}
Parser[T].^^(f)
相当于Parser[T].map(f)
~
,~>
和<~
要求某些输入按特定顺序排列
~>
和<~
从结果中删除输入的一侧case a ~ b
允许模式匹配结果(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
是一个或多个元素的重复|
尝试将输入与其左侧的解析器匹配,如果失败,则会尝试右侧的解析器答案 1 :(得分:1)
怎么样
def resolvePair(s: String): String = {
val open = s.lastIndexOf('{')
val close = s.indexOf('}', open)
if((open >= 0) && (close > open)) {
val (a,b) = s.splitAt(open+1)
val (c,d) = b.splitAt(close-open-1)
resolvePair(a.dropRight(1)+sumString(c).toString+d.drop(1))
} else
s
}
我知道这很丑,但我认为它运作正常。