Scala二十四点游戏(2):表达式计算(二)

jerry Scala 2015年11月25日 收藏

在上篇Scala二十四点游戏(1):表达式计算(一)我们使用Scala实现了四则运算,但还不支持带括号的情况,本篇我们接着看看如处理带括号的情况,
比如表达式 1+2+(3*5)+3+3*(3+(3+5))

括号的情况稍微有些复杂,一层括号比较简单,对于嵌套括号的情况,需要匹配同一层次的括号,好在我们只需要匹配最外面一层括号,其它的可以通过递归函数的方法依次匹配。这里我们定义一个方法,通过栈结构来匹配最外一层括号:

  1. import scala.collection.mutable.Stack
  2.  
  3. def matchBracket(str:String):Option[(Int,Int)] ={
  4. val left = str.indexOf('(')
  5. if(left >=0) {
  6. val stack = Stack[Char]()
  7. val remaining = str substring (left+1)
  8. var index=0
  9. var right=0
  10. for(c <-remaining if right==0){
  11. index=index + 1
  12. c match{
  13. case '(' => stack push c
  14. case ')' => if (stack isEmpty) right= left+index else stack pop
  15. case _ =>
  16. }
  17.  
  18. }
  19.  
  20. Some(left,right)
  21. }else None
  22. }

这个方法匹配最外面一层括号,并给出他们在字符中的位置,我们做个简单的测试

  1. scala> val str="1+2+(3*5)+3+3*(3+(3+5))"
  2. str: String = 1+2+(3*5)+3+3*(3+(3+5))
  3.  
  4. scala> val Some((left,right))=matchBracket(str)
  5. left: Int = 4
  6. right: Int = 8
  7.  
  8. scala> str.charAt(left)
  9. res0: Char = (
  10.  

这个函数成功找到匹配的括号。

对于每个包含括号的表达式,可以有如下形式
part1 ( expr ) part2

因此我们可以实现如下的Bracket 对象来匹配括号表达式

  1. object Bracket{
  2.  
  3. def matchBracket(str:String):Option[(Int,Int)] ={
  4. val left = str.indexOf('(')
  5. if(left >=0) {
  6. val stack = Stack[Char]()
  7. val remaining = str substring (left+1)
  8. var index=0
  9. var right=0
  10. for(c <-remaining if right==0){
  11. index=index + 1
  12. c match{
  13. case '(' => stack push c
  14. case ')' => if (stack isEmpty) right= left+index else stack pop
  15. case _ =>
  16. }
  17.  
  18. }
  19.  
  20. Some(left,right)
  21. }else None
  22. }
  23.  
  24. def apply(part1:String,expr:String,part2:String) =part1+ "(" + expr + ")"+ part2
  25. def unapply(str:String) :Option[(String,String,String)] ={
  26. Bracket.matchBracket(str) match{
  27. case Some((left:Int,right:Int)) =>{
  28. val part1 = if (left == 0) "" else str substring(0, left )
  29. val expr = str substring(left + 1, right)
  30. val part2 = if (right == (str length)-1) "" else str substring (right+1)
  31. Some(part1, expr, part2)
  32. }
  33. case _ => None
  34. }
  35. }
  36. }

修改之前的eval 函数,首先匹配括号表达式:

  1. def eval(str:String):Int = str match {
  2. case Bracket(part1,expr,part2) => eval(part1 + eval(expr) + part2)
  3. case Add(expr1,expr2) => eval(expr1) + eval(expr2)
  4. case Subtract(expr1,expr2) => eval(expr1) - eval(expr2)
  5. case Multiply(expr1,expr2) => eval(expr1) * eval(expr2)
  6. case Divide(expr1,expr2) => eval(expr1) / eval(expr2)
  7. case _ => str toInt
  8.  
  9. }

做些简单的测试:

  1. scala> eval ("1+(3+(4+2)+3+(3+5)+3)+5")
  2. res1: Int = 29
  3.  
  4. scala> eval ("1+2+(3*5)+3+3*(3+(3+5))")
  5. res2: Int = 54
  6.  

这样整数的四则运算的算法基本实现了,当然还不是很完善,比如负数,错误处理等,不过这些对我们解决24问题不是很重要,我们暂时忽略这些问题。