用Python实现复杂的计算器,可以按照“()”、乘除、加减的优先级进行混合运算。主旨是对正则表达式进行学习。

设计思路:

  1.在计算式中搜索最后一个“(”,再搜索和它匹配的“)”,截取两个括号间的表达式cul。

  2.乘除的优先级高,循环搜索cul内的乘除号,进行计算后进行加减计算,得到结果ans。

  3.用ans替换“(cul)”,重新搜索括号,知道将输入的公式简化成没有括号的四则运算。

  4.对最后的四则运算计算结果。流程图如下:

设计时的注意事项:

  1.在简化计算式过程中,如3*(1-3),简化后为3*-2,在进行乘运算的时候会报错。解决措施为将乘数前的负号移至被乘数前。将算术式更换为-3*2。除法也用相同的方法处理。

  2.在出现“--”或“+-”的时候,可以把“--”替换成“+”,把“+-”替换成“-”。

代码分析:

代码的结构是这样的:


执行文件其实没啥说的!

 import os,sys
BASE_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
print(BASE_dir)
sys.path.append(BASE_dir)
from core import main
if __name__ == '__main__':
main.run()

calculato.py就是将文件路径添加到环境变量中

 import re
def mul(processor):      #乘运算
a = re.search(r"(\d+)?[.]?(\d+)[*]", processor).group()[:-1]
b = re.search(r"[*]\d+[.]?(\d+)?", processor).group()[1:]
ans = float(a) * float(b)
ans = str(ans)
processor_past = re.sub(r"\d+[.]?(\d+)?[*]\d+[.]?(\d+)?", ans, processor, count=1)
return processor_past
def div(processor):     #除运算
a = re.search(r"(\d+)?[.]?(\d+)[/]", processor).group()[:-1]
b = re.search(r"[/]\d+[.]?(\d+)?", processor).group()[1:]
ans = float(a) / float(b)
ans = str(ans)
processor_past = re.sub(r"\d+[.]?(\d+)?[/]\d+[.]?(\d+)?", ans, processor, count=1)
return processor_past
def add(processor):      #加运算
a=re.search("(\d+)?[.]?(\d+)[+]",processor).group()[:-1]
b=re.search("[+]\d+[.]?(\d+)?",processor).group()[1:]
ans = float(a)+float(b)
ans = str(ans)
processor_past = re.sub(r"\d+[.]?(\d+)?[+]\d+[.]?(\d+)?",ans,processor,count=1)
return processor_past
def sub(processor):      #减运算
a=re.search("\d+[.]?(\d+)?[-]",processor).group()[:-1]
b=re.search("[-]\d+[.]?(\d+)?",processor).group()[1:]
ans = float(a)-float(b)
ans = str(ans)
processor_past = re.sub(r"\d+[.]?(\d+)?[-]\d+[.]?(\d+)?",ans,processor,count=1)
return processor_past

在func.py中定义了运算的方法,由于形参是字符串形式,需将计算结果转换成字符串,然后将结果和算术式替换:如mul("3*2+1)的返回值是“6+1”。

这里还用了字符串的切片方法,删掉第一个值:[1:],删掉最后一个值为[:-1]。

以乘法为例,"*"前必须为数字,被乘数是小数的话还会有小数点和整数位,所以在正则表达式的查询关键字为r“(\d+)?[.]?(\d+)[*]”,所引出字符串后删掉最后的“*”,而“*”后紧跟的是数字,小数点和小数点后的数为非必须字符。用r"[*]\d+[.]?(\d+)?"查找。

在查询关键字时“*"和”+“为转义字符,要在字符串前加”r“

 import re
from core import func
def find_brackets(cul): #将“()”内表达式分析出来
while re.search("[(].+", cul):
cul = re.search("[(].+", cul).group()[1:]
cul = cul[::-1]
while re.search("[)].+", cul):
cul = re.search("[)].+", cul).group()[1:]
cul = cul[::-1]
return (cul) def change(search,ans,cul): #将运算结果和()里的表达式更换
search = re.sub("[+]", '\+',search)
search = re.sub("[*]", '\*',search)
cul = re.sub("[(]%s[)]"%search,ans,cul)#在正则表达式中插入变量
return cul def change_minus(search, ans, before): # 和move_minus一起移动乘除号后面的负号
search = re.sub("[+]", '\+', search)
search = re.sub("[*]", '\*', search)
after = re.sub(search, ans, before)
return after def move_minus(cul):
b = cul
if re.search(r"(\d+)?[.]?\d+[*][-](\d+)?[.]?\d+?", cul):
a = re.search(r"(\d+)?[.]?\d+[*][-](\d+)?[.]?\d+?", cul).group()
c = a
a = re.sub("[-]", "", a)
a = '-' + a
b = change_minus(c, a, cul)
elif re.search(r"(\d+)?[.]?\d+[/][-](\d+)?[.]?\d+?", cul):
a = re.search(r"(\d+)?[.]?\d+[/][-](\d+)?[.]?\d+?", cul).group()
c = a
a = re.sub("[-]", "", a)
a = '-' + a
b = change_minus(c, a, cul)
return b def mul_div(str_past): #乘除优先级一致,进行乘除运算
ans = str_past
while re.search("[\*]|[/]",ans):
res = re.search("[/]|[\*]",ans).group()
if res == "*":
ans = func.mul(ans)
elif res =="/":
ans = func.div(ans)
return ans def add_reduce(str_past): #加减优先级一致,进行加减运算
ans = str_past
ans = re.sub("--","+",ans)
ans = re.sub(r"[+][-]","-",ans)
while re.search(r"[+]|[-]",ans):
if re.match("-",ans):
break
else:
res = re.search(r"[+]|[-]",ans).group()
if res == "+":
ans = func.add(ans)
elif res =="-":
ans = func.sub(ans)
return ans def cul(str):
cul = str
ans = str
while re.search("[(]",cul):
cul = re.sub("--", "+", cul)
cul = re.sub(r"[+][-]", "-", cul)
cul_1 = find_brackets(cul)
ans = mul_div(cul_1)
ans = add_reduce(ans)
ans = change(cul_1,ans,cul)
cul = ans
cul = move_minus(cul)
ans = move_minus(ans)
ans = mul_div(ans)
ans = add_reduce(ans)
return ans

calcu.py定义了整个计算的流程。

cul()中不断索引括号,将索引出的算术式计算后用结论替代。每简化一轮后检查乘除号后是否有负号的状态。

乘除法的优先级比加减高,可以把乘除的运算放在一起,

while re.search("[\*]|[/]",ans):

用这个方法可以从左到右循环搜索算术式内的乘除运算。

 import re
import os,sys
from core import calcu,func.log
def run():
print("欢迎使用计算器!!!")
while True:
cul = input("请输入计算公式:")
if cul == "exit":
print("退出计算器!")
break
elif re.findall("[(]", cul).__len__() != re.findall("[)]", cul).__len__():
print("括号不匹配!")
elif re.search("[(]|[)]",cul):
print("请使用英文符号!")
elif re.search("[a-z]|[A-Z]",cul):
print("请输入数字!")
else:
ans = calcu.cul(cul)
print(ans)
log.logger(cul,ans)

main.py调用了整个算式的计算过程,并对输入的公式进行了一些纠错措施并在每次计算后将计算式和结论存储在日志中。

 import time
def logger(cul,ans):
fp = open("logger.txt",'a+',encoding="UTF-8")
now = time.time()
fp.write("%s %s=%s\n"%(now,cul,ans))
fp.close()

log.py就是将每次运算的公式和结论存储在日志中。

存在的问题:日志文件应存储在log路径下,但是现在每次执行完会在bin路径下生成新日志文件并进行存储操作。还在想办法改进中!

Python实现的复杂的计算器的代码的更多相关文章

  1. python 利用栈实现复杂计算器

    #第五周的作业--多功能计算器#1.实现加减乘除及括号的优先级的解析,不能使用eval功能,print(eval(equation))#2.解析复杂的计算,与真实的计算器结果一致#用户输入 1 - 2 ...

  2. Python开发——利用正则表达式实现计算器算法

    Python开发--利用正则表达式实现计算器算法 (1)不使用eval()等系统自带的计算方法 (2)实现四则混合运算.括号优先级解析 思路: 1.字符串预处理,将所有空格去除 2.判断是否存在括号运 ...

  3. python超实用的30 个简短的代码片段(三)

    Python是目前最流行的语言之一,它在数据科学.机器学习.web开发.脚本编写.自动化方面被许多人广泛使用. 它的简单和易用性造就了它如此流行的原因. 如果你正在阅读本文,那么你或多或少已经使用过P ...

  4. [转] 三种Python下载url并保存文件的代码

    原文 三种Python下载url并保存文件的代码 利用程序自己编写下载文件挺有意思的. Python中最流行的方法就是通过Http利用urllib或者urllib2模块. 当然你也可以利用ftplib ...

  5. 使用python制作ArcGIS插件(2)代码编写

    使用python制作ArcGIS插件(2)代码编写 by 李远祥 上一章节已经介绍了如何去搭建AddIn的界面,接下来要实现具体的功能,则到了具体的编程环节.由于使用的是python语言进行编程,则开 ...

  6. Python 爬虫的工具列表 附Github代码下载链接

    Python爬虫视频教程零基础小白到scrapy爬虫高手-轻松入门 https://item.taobao.com/item.htm?spm=a1z38n.10677092.0.0.482434a6E ...

  7. Python中生成器和迭代器的区别(代码在Python3.5下测试):

    https://blog.csdn.net/u014745194/article/details/70176117 Python中生成器和迭代器的区别(代码在Python3.5下测试):Num01–& ...

  8. Qt简单项目--加法计算器(详细代码注释)

    Qt的简单案例--加法计算器(详细代码注释) 一.项目结构 二.项目代码 widget.h #ifndef WIDGET_H #define WIDGET_H //预编译指令, 为了避免头文件被重复包 ...

  9. (转)Python新手写出漂亮的爬虫代码2——从json获取信息

    https://blog.csdn.net/weixin_36604953/article/details/78592943 Python新手写出漂亮的爬虫代码2——从json获取信息好久没有写关于爬 ...

随机推荐

  1. eclipse egit(版本回退)

    在公司一年多了,用到的项目都是用svn代码托管,没有git 的用武之地,趁国庆假期稍微自学了一下,然后人比较懒,不愿用原生敲命令行的形式,就在eclipse上学学怎么用git,话说回来用了svn再来学 ...

  2. pandas.DataFrame.to_excel

    1. file_name = 'aa.xlsx' df.to_excel(file_name) #这种file_name不能重复,已经生成过的就会报错 writer = pd.ExcelWriter( ...

  3. Handling Event

    [Handling Event] 1.React events are named using camelCase 2.You must call preventDefault explicitly ...

  4. metasploit framework(七):密码嗅探

    run 当嗅探到流量中的用户密码信息时打印出来,目前只支持FTP,http get , pop3 还可以对抓包文件,进行密码提取,设置需要提取的文件路径 run就能提取里面的用户密码信息 查看和停掉某 ...

  5. 健壮的网络编程IO函数-RIO包

    RIO包 简介 Rio包即为Robust io函数包.包中函数是对Linux基本I/O函数的封装,使其更加健壮.高效,更适用于网络编程. 分析 Rio包由rio_t结构体和系列函数组成. 首先是两个不 ...

  6. SpringMVC包括哪些组件

      1 映射器 1.1作用:Handlermapping根据url查找Handler   2 适配器 2.1作用:HandlerAdapter执行Handler   3 解析器 3.1作用:View ...

  7. centos7.2 增加3T的XFS模式分区

    parted -l 查看分区情况与要分区的设备 # parted /dev/sda                   #选定要操作的硬盘     此时命令提示符会变成(parted)    (par ...

  8. Maven 基本参数

    -h,--help                              Display help information-am,--also-make                       ...

  9. WEB 自动化思路

    前期做了一个关键字驱动模型的WEB自动化项目,特意写文章归纳和总结下. 框架架构图 已经实现的部分: 1. 读写excel数据模板 2.配置中心,支持properties,xml格式的配置文件 3.参 ...

  10. delet[] 和delete

    string *stringPtr1 = new string; string *stringPtr2 = new string[100]; …… delete stringPtr1; delete ...