本文最后更新于187 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com
go 命令行计算器:接受用户输入的算数表达式,并输出结果
示例
请输入一个计算式:
-9*8*(-2)-88/5
-9*8*(-2)-88/5的值为:
126.4
进程 已完成,退出代码为 0
思路:
使用栈先入后出的特点和计算符的优先级,把获取的字符串转为后缀表达式,并同时使用栈来计算结果
1.定义符号优先级(使用map映射绑定)
2.定义栈
3.中缀表达式转后缀表达式函数
4.计算后缀表达式
5.后缀表达式计算函数
6.输入式子合法性检测
7.去除结果小数点后面多余的零
各部分代码
1.定义符号优先级(使用map映射绑定)
var priority = map[rune]int{
'%': 2,
'+': 1,
'-': 1,
'*': 2,
'/': 2,
'(': 0,
}
2.定义栈结构
// 实现栈结构
type SliceStack struct {
dataStack []interface{}
}
// 创建一个新的初始栈
func NewSliceStack() *SliceStack {
return &SliceStack{}
}
// 在栈顶放入数据
func (s *SliceStack) Push(data interface{}) {
s.dataStack = append(s.dataStack, data)
//append函数:在原切片的末尾添加元素
}
// 栈最上面的数据出栈
func (s *SliceStack) Pop() interface{} {
if len(s.dataStack) == 0 {
return nil
}
slice := s.dataStack[len(s.dataStack)-1]
s.dataStack = s.dataStack[:len(s.dataStack)-1]
//把栈顶下移一位
return slice
}
// 查看栈顶第一个元素
func (s *SliceStack) Peek() interface{} {
if len(s.dataStack) == 0 {
return nil
}
return s.dataStack[len(s.dataStack)-1]
}
// 判断栈是否空
func (s *SliceStack) IsEmpty() bool {
return len(s.dataStack) == 0
}
3.中缀表达式转后缀表达式函数
// 中缀表达式转后缀表达式
func convert(shuru string) []interface{} {
//定义一个存放处理后的字符的切片
var inter []interface{}
//创建一个栈,用于存放运算符
houzhui := NewSliceStack()
for i := 0; i < len(shuru); i++ {
//转换输入的字段为rune类型方便值的判断
char := rune(shuru[i])
//字符为空格时,跳过此次循环
if char == ' ' {
continue
}
//处理正负数字
if unicode.IsDigit(char) || char == '.' || (char == '-' && (i == 0 || (i > 0 && (rune(shuru[i-1]) == '(' || rune(shuru[i-1]) == '+' || rune(shuru[i-1]) == '-' || rune(shuru[i-1]) == '*' || rune(shuru[i-1]) == '/')))) {
num := ""
if char == '-' {
num += string(char)
i++
char = rune(shuru[i])
}
for i < len(shuru) && (unicode.IsDigit(char) || char == '.') {
num += string(char)
i++
if i < len(shuru) {
char = rune(shuru[i])
}
}
i-- //回退一部,因为外层也有一个 i++
//将字符转化为浮点型
value, _ := strconv.ParseFloat(num, 64)
//将处理过后的数据放入inter切片中存放
inter = append(inter, value)
//在符号为"("的情况下直接放入字符栈中
} else if char == '(' {
houzhui.Push(char)
} else if char == ')' {
//在存放运算符的栈不为空,并且栈顶字符不为"("的情况下
for !houzhui.IsEmpty() && houzhui.Peek().(rune) != '(' {
//把运算符栈中的运算符取出放进inter中
inter = append(inter, houzhui.Pop())
}
//取出栈中"("
houzhui.Pop()
} else {
//处理运算符优先级
//在栈不为空,并且新的运算符优先级比栈顶的小的情况下
for !houzhui.IsEmpty() && priority[houzhui.Peek().(rune)] >= priority[char] {
//把运算符放入inter中
inter = append(inter, houzhui.Pop())
}
houzhui.Push(char)
}
}
//把剩余的操作符全部放入inter切片中
for !houzhui.IsEmpty() {
inter = append(inter, houzhui.Pop())
}
//返回切片
return inter
}
计算后缀表达式
// 计算后缀表达式
// 计算后缀表达式
func computeDpostfixshuru(inter []interface{}) float64 {
//创建一个用存放数值
stored := NewSliceStack()
//遍历数值
for _, value := range inter {
//判断遍历数值的类型
switch value.(type) {
case float64:
//当类型为float64时,把值压入栈中
stored.Push(value)
case rune:
//当值为rune时判定为计算符,调用计算函数
calculatingFunction(stored, value.(rune))
}
}
//返回栈低最后一个值作为结果
return stored.Pop().(float64)
}
计算函数
// 计算函数
func calculatingFunction(stored *SliceStack, operator rune) {
//取出两个操作数
num1 := stored.Pop().(float64)
num2 := stored.Pop().(float64)
var result float64
switch operator {
case '+':
result = num2 + num1
case '-':
result = num2 - num1
case '*':
result = num2 * num1
case '/':
//被除数为零时输出错误和终止程序
if num1 == 0 {
fmt.Println("错误:计算过程中出现被除数等于零的情况,请检查算式合法性")
os.Exit(1)
} //除法注意先后顺续不要错
result = num2 / num1
case '%':
result = math.Mod(num2, num1)
}
//将结果压回栈
stored.Push(result)
}
6.检测输入式子合法性
func validateshuru(expr string) error {
// 移除空格
expr = strings.ReplaceAll(expr, " ", "")
// 检查是否包含非法字符
if matched, _ := regexp.MatchString(`[^0-9+\-*/().% ]`, expr); matched {
return fmt.Errorf("错误:输入字符不合法")
}
// 检查括号是否成对出现
if strings.Count(expr, "(") != strings.Count(expr, ")") {
return fmt.Errorf("错误:输入括号不匹配")
}
// 检查开头和结尾是否为非法字符
if matched, _ := regexp.MatchString(`^[*/%]|\s$`, expr); matched {
return fmt.Errorf("错误:开头或者结尾字符不合法")
}
// 检查连续的操作符
if matched, _ := regexp.MatchString(`\+\+|--|\*\*|%%|\(\)|//`, expr); matched {
return fmt.Errorf("错误:出现连续的符号")
}
if matched, _ := regexp.MatchString(`/0`, expr); matched {
return fmt.Errorf("错误:0不能出现在/0后面")
}
return nil
}
7.动态去除小数点后面的零
// 动态去除小数点后的零
func removeZero(f float64) string {
s := fmt.Sprintf("%f", f)
s = strings.TrimRight(s, "0")
//检查移除多余零最后一位是否为‘.’结尾
if strings.HasSuffix(s, ".") {
s = strings.TrimRight(s, ".")
}
return s
}
完整代码
package main
import (
"bufio"
"fmt"
"math"
"os"
"regexp"
"strconv"
"strings"
"unicode"
)
// 1.定义符号优先级
// 2.定义栈
// 3.中缀转后缀表达式
// 4.计算后缀表达式
// 5.计算函数
// 6.检验输入式子合法性
// 7.动态去除小数点后的零
// map映射绑定字符优先级
var priority = map[rune]int{
'%': 2,
'+': 1,
'-': 1,
'*': 2,
'/': 2,
'(': 0,
}
// 实现栈结构
type SliceStack struct {
dataStack []interface{}
}
// 创建一个新的初始栈
func NewSliceStack() *SliceStack {
return &SliceStack{}
}
// 在栈顶放入数据
func (s *SliceStack) Push(data interface{}) {
s.dataStack = append(s.dataStack, data)
//append函数:在原切片的末尾添加元素
}
// 栈最上面的数据出栈
func (s *SliceStack) Pop() interface{} {
if len(s.dataStack) == 0 {
return nil
}
slice := s.dataStack[len(s.dataStack)-1]
s.dataStack = s.dataStack[:len(s.dataStack)-1]
//把栈顶下移一位
return slice
}
// 查看栈顶第一个元素
func (s *SliceStack) Peek() interface{} {
if len(s.dataStack) == 0 {
return nil
}
return s.dataStack[len(s.dataStack)-1]
}
// 判断栈是否空
func (s *SliceStack) IsEmpty() bool {
return len(s.dataStack) == 0
}
// 中缀表达式转后缀表达式
func convert(shuru string) []interface{} {
//定义一个存放处理后的字符的切片
var inter []interface{}
//创建一个栈,用于存放运算符
houzhui := NewSliceStack()
for i := 0; i < len(shuru); i++ {
//转换输入的字段为rune类型方便值的判断
char := rune(shuru[i])
//字符为空格时,跳过此次循环
if char == ' ' {
continue
}
//处理正负数字
if unicode.IsDigit(char) || char == '.' || (char == '-' && (i == 0 || (i > 0 && (rune(shuru[i-1]) == '(' || rune(shuru[i-1]) == '+' || rune(shuru[i-1]) == '-' || rune(shuru[i-1]) == '*' || rune(shuru[i-1]) == '/')))) {
num := ""
if char == '-' {
num += string(char)
i++
char = rune(shuru[i])
}
for i < len(shuru) && (unicode.IsDigit(char) || char == '.') {
num += string(char)
i++
if i < len(shuru) {
char = rune(shuru[i])
}
}
i-- //回退一部,因为外层也有一个 i++
//将字符转化为浮点型
value, _ := strconv.ParseFloat(num, 64)
//将处理过后的数据放入inter切片中存放
inter = append(inter, value)
//在符号为"("的情况下直接放入字符栈中
} else if char == '(' {
houzhui.Push(char)
} else if char == ')' {
//在存放运算符的栈不为空,并且栈顶字符不为"("的情况下
for !houzhui.IsEmpty() && houzhui.Peek().(rune) != '(' {
//把运算符栈中的运算符取出放进inter中
inter = append(inter, houzhui.Pop())
}
//取出栈中"("
houzhui.Pop()
} else {
//处理运算符优先级
//在栈不为空,并且新的运算符优先级比栈顶的小的情况下
for !houzhui.IsEmpty() && priority[houzhui.Peek().(rune)] >= priority[char] {
//把运算符放入inter中
inter = append(inter, houzhui.Pop())
}
houzhui.Push(char)
}
}
//把剩余的操作符全部放入inter切片中
for !houzhui.IsEmpty() {
inter = append(inter, houzhui.Pop())
}
//返回切片
return inter
}
// 计算后缀表达式
func computeDpostfixshuru(inter []interface{}) float64 {
//创建一个用存放数值
stored := NewSliceStack()
//遍历数值
for _, value := range inter {
//判断遍历数值的类型
switch value.(type) {
case float64:
//当类型为float64时,把值压入栈中
stored.Push(value)
case rune:
//当值为rune时判定为计算符,调用计算函数
calculatingFunction(stored, value.(rune))
}
}
//返回栈低最后一个值作为结果
return stored.Pop().(float64)
}
// 计算函数
func calculatingFunction(stored *SliceStack, operator rune) {
//取出两个操作数
num1 := stored.Pop().(float64)
num2 := stored.Pop().(float64)
var result float64
switch operator {
case '+':
result = num2 + num1
case '-':
result = num2 - num1
case '*':
result = num2 * num1
case '/':
if num1 == 0 {
fmt.Println("错误:计算过程中出现被除数等于零的情况,请检查算式合法性")
os.Exit(1)
} //除法注意先后顺续不要错
result = num2 / num1
case '%':
result = math.Mod(num2, num1)
}
//将结果压回栈
stored.Push(result)
}
// 式子合法性判断
func validateshuru(expr string) error {
// 移除空格
expr = strings.ReplaceAll(expr, " ", "")
// 检查是否包含非法字符
if matched, _ := regexp.MatchString(`[^0-9+\-*/().% ]`, expr); matched {
return fmt.Errorf("错误:输入字符不合法")
}
// 检查括号是否成对出现
if strings.Count(expr, "(") != strings.Count(expr, ")") {
return fmt.Errorf("错误:输入括号不匹配")
}
// 检查开头和结尾是否为非法字符
if matched, _ := regexp.MatchString(`^[*/%]|\s$`, expr); matched {
return fmt.Errorf("错误:开头或者结尾字符不合法")
}
// 检查连续的操作符
if matched, _ := regexp.MatchString(`\+\+|--|\*\*|%%|\(\)|//`, expr); matched {
return fmt.Errorf("错误:出现连续的符号")
}
if matched, _ := regexp.MatchString(`/0`, expr); matched {
return fmt.Errorf("错误:0不能出现在/0后面")
}
return nil
}
// 动态去除小数点后的零
func removeZero(f float64) string {
s := fmt.Sprintf("%f", f)
s = strings.TrimRight(s, "0")
//检查移除多余零最后一位是否为‘.’结尾
if strings.HasSuffix(s, ".") {
s = strings.TrimRight(s, ".")
}
return s
}
func main() {
fmt.Println("请输入一个计算式:")
// 创建一个新的读取器
reader := bufio.NewReader(os.Stdin)
// 读取输入的一整行
shuru, err := reader.ReadString('\n')
if err != nil {
fmt.Println("读取输入时出错:", err)
return
}
shuru = strings.TrimSuffix(shuru, "\n")
panduan := validateshuru(shuru)
if panduan == nil {
postfix := convert(shuru)
result := computeDpostfixshuru(postfix)
results := removeZero(result)
fmt.Printf(" %s 的值为:\n%v", shuru, results)
} else {
fmt.Println(panduan)
}
}