# 加减乘除带括号

  • 定义结果字段res, 原理是相加”a + b“, 如果是b是负数 那么 a+(-b)

  • s 为要遍历的字符串,尾部加”+“

  • 遍历前定义上一次的操作符pos为1,也就是”+“

  • 遍历到数字的时候,定义subStr子串,代表上一次的保存的值

  • 首先只考虑加减的时候,遍历到操作符的时候,只要把上一次的操作符pos和subStr相乘,得到数字和res相加,把pos设为当前操作符,subStr设为”“

  • 有了乘除,要考虑优先级,如果碰到*/,就把subStr和pos存储起来,等下一次再遇到操作符的时候取出计算后重新赋值subStr,再按照加减的算法继续

  • 有括号的情况,用递归,如果遇到左括号,继续循环,直到遇到最后一个右括号,这中间的字符串取出,赋值subStr,比如 5+(8-9*(2-1)), 8-9*(2-1)作为新的字符串计算

function caculator(s) {
  s = s + '+'

  let res = 0 // 结果
  let subStr = ''
  let pos = 1 // 上一次的操作符
  let tempData = [] // 存储上一次的 subStr 和 操作符

  let zuokuoArr = [] // 左括号栈
  let num = 0 // 配合 左括号栈 匹配到右括号时子串长度

  let i = 0

  for (i; i < s.length; i++) {
    var ch = s.charAt(i)

    // 如果碰到左括号,左括号栈 入栈
    if (ch === '(') {
      zuokuoArr.push('(')
    }
    // 如果碰到右括号,左括号栈 出栈
    if (ch === ')') {
      zuokuoArr.pop()
    }

    // 如果左括号栈内还有左括号,继续循环,子串长度 + 1
    if (zuokuoArr.length > 0) {
      num++
      continue
    }

    // 如果发现左括号栈 长度为0 并且 有子串, 那么递归单独计算子串,把结果赋值给subStr, 子串长度设为0,继续循环
    if (zuokuoArr.length === 0 && num > 0) {
      const t = s.substring(i - num + 1, i)
      num = 0
      subStr = caculator(t)
      continue
    }

    /////////////////// 以上是括号逻辑 ////////////////////
    ////////////////// 下面是计算逻辑 ////////////////////

    // 如果发现 是数字,继续循环,得到完整数字
    if (ch >= 0 && ch <= 9) {
      subStr = subStr + ch
      continue
    }

    // 如果碰到 +-*/
    if (['+', '-', '*', '/'].includes(ch)) {
      // 先判断前面的是否存储上一次的subStr, 计算得出当前subStr
      if (tempData.length > 0) {
        const op = tempData.pop()
        const d = tempData.pop()
        if (op === '*') {
          subStr = d * subStr
        } else if (op === '/') {
          subStr = d / subStr
        }
      }

      // 如果是 + - ,计算结果,如果是*/,存储subStr和操作符
      switch (ch) {
        case '+':
          res += pos * subStr
          subStr = ''
          pos = 1
          break
        case '-':
          res += pos * subStr
          subStr = ''
          pos = -1
          break
        case '*':
          tempData.push(subStr)
          tempData.push(ch)
          subStr = ''
          break
        case '/':
          tempData.push(subStr)
          tempData.push(ch)
          subStr = ''
          break
        default:
          break
      }
    }
  }

  return res
}

console.log(caculator('4-4*(3+2)-(4)+4'))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
最后更新时间: 5/26/2021, 5:52:52 PM