我试图在Scala中将公式转换为RPN(反向波兰表示法)。
RPN:https://en.wikipedia.org/wiki/Reverse_Polish_notation
但是我无法编写任何代码。
object RPNCalclator {
def convertToRPN(expr: String): String = {
???
}
def calcRPN(expr: String): Double = {
???
}
def main(args: Array[String]): Unit = {
val expr = "4 * ( 8 + 4 + 3 )"
val rpn = convertToRPN(expr) // " 4 8 4 3 + + *"
println(calcRPN(rpn))
}
}
我想弄清楚如何编写convertToRPN
代码。
例如,
4 + 5
-> 4 5 +
1 + 2 * 3 + 4
-> 1 2 3 * 4 + +
( 1 + 2 ) * ( 3 + 4 )
-> 1 2 + 3 4 + *
答案 0 :(得分:1)
您确实需要一个完整的语法解析器,但这有点脏。
def convertToRPN(expr :String, ops :String = "") :String = {
val str = expr.strip
if (str.isEmpty) ops.mkString(" ") //done?
else if (str.head == '(') { //start of parentheses
val spltAt = str.iterator.scanLeft(0){case (lvl,c) =>
if (c=='(') lvl+1 else if (c==')') lvl-1 else lvl
}.drop(1).indexOf(0)
val (paren, s) = str.splitAt(spltAt)
s"${convertToRPN(paren.tail)} ${convertToRPN(s.tail, ops)}"
} else {
val (token, s) = str.span(_ != ' ')
if (util.Try(token.toDouble).isSuccess) //is number
s"$token ${convertToRPN(s, ops)}"
else if (token matches "[*/]") //is higher precedence op
convertToRPN(s, s"$token$ops")
else if (token matches "[-+]") { //is lower precedence op
ops.headOption.fold(convertToRPN(s, s"$token$ops")){
case '-'|'+' => convertToRPN(s, s"$token$ops")
case _ =>
s"${ops.head} ${convertToRPN(s, s"$token${ops.tail}")}"
}
} else throw new Error(s"unable to parse token: $token")
}
}
是的,我知道,对于“ quick-n-dirty”来说,这是很多代码。它是递归的,但不是尾递归的。 (那会有点脏。)
这应该适用于大多数数字格式,包括负数,但是它确实依赖于空格分隔符,因此不会解析诸如1+2
之类的东西。
calcRPN()
应该相对容易。