golang支持括号运算的计算器

coding

现在需要实现一个计算器函数,输入是一个字符串格式的数学运算表达式,要求计算出该表达式的最终结果。表达式的操作符支持加减乘除和小括号。
思路:利用stack,将低优先级的运算压栈,遇到相同优先级的则计算第一个符号。右括号的,把括号内式子单独计算,并把结果代入原式子继续计算

package main

import (

"errors"

"fmt"

"strconv"

"log"

)

type Stack struct {

elements []interface{} //elements

}

func NewStack() *Stack {

return &Stack{make([]interface{}, 0, 100)}

}

func (s *Stack) Push(value ...interface{}) {

s.elements = append(s.elements, value...)

}

//返回下一个元素

func (s *Stack) Top() (value interface{}) {

if s.Size() > 0 {

return s.elements[s.Size()-1]

}

return nil //read empty s

}

//返回下一个元素,并从Stack移除元素

func (s *Stack) Pop() (value interface{}, err error) {

if s.Size() > 0 {

value = s.elements[s.Size()-1]

s.elements = s.elements[:s.Size()-1]

return

}

return nil, errors.New("s is empty") //read empty s

}

//Stack的size

func (s *Stack) Size() (int) {

return len(s.elements)

}

//是否为空

func (s *Stack) Empty() (bool) {

if s.elements == nil || s.Size() == 0 {

return true

}

return false

}

//打印

func (s *Stack) Print() {

for i := len(s.elements) - 1; i >= 0; i-- {

fmt.Println(i, "=>", s.elements[i])

}

}

type Calculator struct {

stDat *Stack

stSym *Stack

}

func NewCalculator() *Calculator {

return &Calculator{NewStack(), NewStack()}

}

func math(num1, num2 float64, sym byte) (result float64) {

switch sym {

case '+':

result = num1 + num2

case '-':

result = num1 - num2

case '*':

result = num1 * num2

case '/':

result = num1 / num2

}

//fmt.Println("math result:", result)

return

}

func (c *Calculator) Step(num float64, sym byte) error {

// 判断栈顶符合与当前符号运算优先级。

// 如果sym不高于栈顶符号,则取出数据栈顶数字、符号栈顶符号 与 num 运算,并将结果压入数据栈,sym压入符号栈。

// 如果sym优先级更高,则分别将 num, sym 压入数据栈和符号栈。

// 如果 sym = '\n' 表示算式结束,依次出栈运算。

if sym == '\n' {

if c.stSym.Size() == 0 {

c.stDat.Push(num)

} else {

length := c.stSym.Size()

for i:=0; i < length; i++ {

symbol, _ := c.stSym.Pop()

ifc, _ := c.stDat.Pop()

num1 := ifc.(float64)

num = math(num1, num, symbol.(byte))

}

c.stDat.Push(num)

}

} else {

if c.stSym.Size() != 0 {

tSymbol := c.stSym.Top().(byte)

pc := priorityCompare(tSymbol, sym)

switch {

case pc < 0:

c.stDat.Push(num)

c.stSym.Push(sym)

case pc >= 0:

c.stSym.Pop()

ifc, _ := c.stDat.Pop()

num1 := ifc.(float64)

c.stDat.Push(math(num1, num, tSymbol))

c.stSym.Push(sym)

}

} else {

c.stDat.Push(num)

c.stSym.Push(sym)

}

}

return nil

}

func (c *Calculator) Result() (result float64, err error) {

if c.stSym.Empty() && c.stDat.Size() == 1 {

result = c.stDat.Top().(float64)

} else {

//计算式未结束或者计算式有误

err = errors.New("计算式未结束或者计算式有误")

}

return

}

// 比较运算符优先级,return >0,则s1高于s2; =0,则s1、s2相同; <0,则s1低于s2

func priorityCompare(s1, s2 byte) int {

level := func(sym byte) int {

lvl := 0

switch sym {

case '+', '-':

lvl = 1

case '*', '/':

lvl = 2

}

return lvl

}

return level(s1) - level(s2)

}

func Calculate(str []byte) (result float64, err error) {

fmt.Println("str:", string(str))

cal := NewCalculator()

sNum, num := make([]byte, 0, 100), 0.0

for idx := 0; idx < len(str); idx++ {

c := str[idx]

switch c {

case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':

sNum = append(sNum, c)

case '+', '-', '*', '/':

if (len(sNum) > 0 && num != 0.0) || (len(sNum) == 0 && num == 0.0) {

err = errors.New("计算式有误")

return

}

if len(sNum) > 0 {

strNum := string(sNum)

intNum, _ := strconv.Atoi(strNum)

num = float64(intNum)

}

cal.Step(num, c)

sNum, num = make([]byte, 0, 100), 0.0

case '(':

idx++

Loop:

for j := idx; j < len(str); j++ {

if str[j] == ')' {

num, err = Calculate(str[idx:j])

if err != nil {

return

}

idx = j

break Loop

}

}

default:

err = errors.New(fmt.Sprintf("无效符号: %s", c))

return

}

}

// 扫描结束

if (len(sNum) > 0 && num != 0.0) || (len(sNum) == 0 && num == 0.0) {

err = errors.New("计算式有误")

return

}

if len(sNum) > 0 {

strNum := string(sNum)

intNum, _ := strconv.Atoi(strNum)

num = float64(intNum)

}

cal.Step(num, '\n')

return cal.Result()

}

func main() {

express := []byte("123+(3+5*4)+4-(2*5+6*3/2)")

//express := []byte("3+5")

result, err := Calculate(express)

if err != nil {

log.Fatalln(err)

}

fmt.Println("result:", result)

}

以上是 golang支持括号运算的计算器 的全部内容, 来源链接: utcz.com/z/508623.html

回到顶部