开发要求:
开发一个简单的 python 计算器:
实现加减乘除及优先级解析;
用户输入类似这样的表达式: 1 - 2*((60-30 +(-40/5)*(9-2*5/3+7/3*99/4*2998 + 10*568/14))-(-4*3)/(16-3*2))
等类似公式后, 必须自己解析里面的 (),+,-,*,/ 符号和公式 (不能调用 eval 等类似的功能实现, 运算后得出结果)
计算结果必须与真实的计算器得出结果一致;
1. 功能分析:
用户输入一个类似这样 3*( 4+ 50 )-(( 100 + 40 )*5/2- 3*2* 2/4+9)*((( 3 + 4)-4)-4) 这样的表达式,
假设表达式里面除了包含空格,'+','-','*','/'和括号再无其他特殊符号,
然后自己动手写代码解析其中的表达式, 实现加减乘除,
最后得出的结果与真实的计算机所算的结果必须一致.
2. 所需要的知识点:
1> 字符串的处理;
2> 正则表达式的运用;
3> 函数递归;
3. 程序实现流程分析:
1> 用正则表达式处理字符串, 只提取其中的数字和运算符, 并转换成列表
2> 编写一个函数, 处理没有括号的基本运算的基本表达式
3> 再写一个函数递归处理带有括号的函数, 先计算最内部括号中的表达式, 然后将最内部的括号替换为计算后的结果, 在递归外部一层的, 最后返回的就是所需的结果
4. 具体实现过程:
- import re, sys
- def input_str():
- """
- 输入表达式
- return: 返回有限的表达式
- """welcome_str =" 超级计算器 "print(welcome_str.center(50,'*'),'\n') # 输出欢迎界面
- while True:
- iput = input("请输入你要计算的表达式 [q: 退出]:").strip()
- if iput == 'q': # 退出计算
- sys.exit("bye-bye")
- elif len(iput) == 0:
- continue
- else:
- iput = re.sub('\s*', '', iput) # 去除空格
- return iput
- def chengchu(expression):
- """
- 乘除运算
- :param expression: 表达式
- :return: 返回没有乘除的表达式 / 最终的计算结果
- """val = re.search("\d+\.?\d*[\*\/]+[\+\-]?\d+\.?\d*", expression) #匹配乘除号, 能识别小数点和正负数, 类似:['121.121*-121.12','121/12.223','3.4*4.5'];
- if not val: #如果不存在乘除, 就直接返回表达式;
- return expression
- else:
- data = re.search("\d+\.?\d*[\*\/]+[\+\-]?\d+\.?\d*", expression).group()
- if len(data.split("*"))> 1: #以乘号分割
- part1, part2 = data.split("*")
- value = float(part1) * float(part2)
- else:
- part1, part2 = data.split("/")
- if float(part2) == 0: #除数为 0 则为无效, 退出
- sys.exit("除数为 0, 计算表达式失败!!!")
- value = float(part1) / float(part2)
- s1, s2 = re.split("\d+\.?\d*[\*\/]+[\+\-]?\d+\.?\d*", expression, 1)
- next_expression = "%s%s%s" % (s1, value, s2)
- return chengchu(next_expression)
- def jiajian(expression):
- """
- 加减运算
- :param expression: 表达式
- :return: 返回没有计算的加减表达式 / 最终的计算结果
- """expression = expression.replace("+-","-") # 替换表达式
- expression = expression.replace("--", "+") # 替换表达式
- expression = expression.replace("++", "+") # 替换表达式
- expression = expression.replace("-+", "-") # 替换表达式
- val = re.search("\-?\d+\.?\d*[\+\-]{1}\d+\.?\d*", expression) # 匹配加减
- if not val: # 如果不存在乘除, 就直接返回表达式;
- return expression
- else:
- data = re.search("\-?\d+\.?\d*[\+\-]{1}\d+\.?\d*", expression).group()
- if len(data.split("+"))> 1: #以乘号分割
- part1, part2 = data.split("+")
- value = float(part1) + float(part2)
- elif data.startswith("-"): #判断是否为负数开头
- part0, part1, part2 = data.split("-")
- value = -float(part1) - float(part2)
- else:
- part1, part2 = data.split("-")
- value = float(part1) - float(part2)
- s1, s2 = re.split("\-?\d+\.?\d*[\+\-]{1}\d+\.?\d*", expression, 1)
- next_expression = "%s%s%s" % (s1, value, s2)
- return jiajian(next_expression)
- def remove_bracket(expression):
- """
- Function: 去小括号运算
- :param expression: 表达式
- :return: 结果
- """
- # 取最小括号内容:
- # 安组匹配, 将括号内容按组匹配, 过滤内容不存在括号即为最内层括号
- if not re.search(r"\(([^()])+\)", expression): #判断小括号, 如果不存在直接计算.
- ret1 = chengchu(expression)
- ret2 = jiajian(ret1)
- return ret2
- else:
- data = re.search(r"\(([^()]+)\)", expression).group() #取优先级最高的括号
- # '( 4+ 50 )'
- data = data.strip("[\(\)]") #去掉括号, 格式: strip([chars])
- # '4+ 50'
- # 遵守先乘除后加减
- ret1 = chengchu(data)
- ret2 = jiajian(ret1)
- part1, replace_str, part2 = re.split(r"\(([^()]+)\)", expression, 1)
- expression1 = "%s%s%s" % (part1, ret2, part2) # 将小括号的计算结果替换成表达式;
- return remove_bracket(expression1)
- if __name__ == "__main__":
- try:
- expression = input_str()
- # expression = "3*( 4+ 50 )-(( 100 + 40 )*5/2- 3*2* 2/4+9)*((( 3 + 4)-4)-4)"
- result = eval(expression) #用 eval 计算验证值;
- expression = expression.replace("","") #除了表达式中空格;
- ret = remove_bracket(expression) #用函数计算式得出的记过;
- result = float(result)
- ret = float(ret)
- if result == ret: #比较 2 种方式的计算结果, 正确则输出结果
- print("eval 计算结果: %s" % result)
- print("表达式计算结果: %s" % ret)
- else: #不正确则提示异常, 并返回结果
- print("计算结果异常, 请重新检查!")
- print("eval 计算结果: %s" % result)
- print("表达式计算结果: %s" % ret)
- except(SystemError, NameError, SyntaxError, ValueError, TypeError):
- print("输入表达式不合法, 请重新检查")
来源: http://www.bubuko.com/infodetail-2659502.html