计算器的Golang实现, 支持 +-*/,并会判断表达式是否合法
package code
import (
"strconv"
"unicode"
)
type Calculator struct {
origin string
s string
left int
signMap map[byte]bool
}
func NewCalculator(s string) Calculator {
signMap := map[byte]bool{
'+': true,
'-': true,
'*': true,
'/': true,
'(': true,
')': true,
' ': true,
}
return Calculator{
origin: s,
s: s,
left: 0,
signMap: signMap,
}
}
func (cal *Calculator) Execuate() int {
stack := NewStack()
num := 0
numFlag := false
emptyFlag := false
sign := '+'
//往前遍历字符串
for len(cal.s) > 0 {
c := cal.s[0]
cal.s = cal.s[1:]
if c == ' ' {
emptyFlag = true
continue
}
//判断是不是数字,考虑到连续累加
if unicode.IsDigit(rune(c)) {
if numFlag {
//数字之间不能有空格
if emptyFlag {
panic(cal.origin + ": express error, empty can not between in numbers")
}
} else {
numFlag = true
}
num = num*10 + (int(c) - int('0'))
} else {
numFlag = false
if _, ok := cal.signMap[c]; !ok {
panic(cal.origin + ": express error, invaild sign:" + string(c))
}
}
emptyFlag = false
//如果是(,递归处理,直到 碰到)弹出,结果返回
if c == '(' {
cal.left++
num = cal.Execuate()
}
//是操作符,或者到了字符串最后,进行sush操作
if len(cal.s) == 0 || !unicode.IsDigit(rune(c)) {
switch sign {
case '+': //直接入stack
stack.Push(num)
case '-': //变成负数,再入stack
num = 0 - num
stack.Push(num)
case '*': //取出statck的top元素并弹出,相乘,再入stack
v, _ := stack.Peek()
stack.Pop()
stack.Push(num * v)
case '/': //取出statck的top元素并弹出,相乘,再入stack
v, _ := stack.Peek()
stack.Pop()
stack.Push(v / num)
}
sign = rune(c)
num = 0
numFlag = false
}
if c == ')' {
cal.left--
if cal.left < 0 {
panic(cal.origin + ": express error, more )")
}
break
}
}
if len(cal.s) == 0 && cal.left > 0 {
panic(cal.origin + ":" + cal.s + ": express error, more (: " + strconv.Itoa(cal.left))
}
//statck求和,返回
return stack.Sum()
}