文章目录提示:本计算器是一个不带界面的,只需要将要计算的计算式传入就可以使用
- 前言
- 一、计算器功能
- 二、计算器设计思想
- 1.复杂运算简单化
- 2.不带括号的计算式处理
- 3.不带括号的计算式的计算
- 3.1 Python内置函数eval()
- 3.2 特殊计算处理
- 3.3 调用eval()将特殊计算处理完成后的计算式进行最后计算
- 4.最后的计算
- 源码
- 计算式字符串处理层(文件名:CalculatorDataConller.py)
- 计算层(文件名:CalculatorCalculate.py)
- 特殊计算处理层(文件名:CalculatorSpecialCalculating.py)
- 调用层(文件名:CalculatorInterface.py)
- 源码文件
前言
对数 输入规则:底数log真数
开方 输入规则:√被开发数
阶乘 输入规则:正整数!
三角函数 接收数据的单位为:角度
提示:以下是本篇文章正文内容,下面案例可供参考
一、计算器功能计算器可以实现:
加(+)、减(-)、乘(*)、除(/)、整除(//)、求余(%)
对数(log)、乘方(**)、开根(√)、阶乘(!)、正弦(sin)
余弦(cos)、正切(tan)、及它们的符合正确语法的复合运算
二、计算器设计思想 1.复杂运算简单化
一个计算式中可能会出现多个括号,括号中是一个小的运算式;计算器先将整个计算式按括号拆分成一个列表,并计算括号中的小计算式,用结果替换括号部分在列表中的位置;重复这个步骤,整个计算式被拆分为没有括号列表
# 如: '(2log4+10**2+20)-100+50/10*(100+2+6)' # 去括号后: ['122', '-100+50/10*', '108']2.不带括号的计算式处理
将不带括号的计算式(可以是括号内部的小计算式),从基本符号([‘+’, ‘-’, ‘*’, ‘/’, ‘%’])处拆分为几个部分,并用一个列表进行存储。
注意:上述符号在拆分过程中,会将符号与跟符号相关的数字分离;其他运算符看作特殊的运算符,如:log、!、cos等,在拆分过程中不会将符号与作用的数字相分离,而是当作一个整体
# 如: '122-100+50/10*108+2log4+cos90+6!+2**2*2' # 拆分后: ['122', '-', '100', '+', '50', '/', '10', '*', '108', '+', '2log4', '+', 'cos90', '+', '6!', '+', '2**2', '*', '2']3.不带括号的计算式的计算 3.1 Python内置函数eval()
python内置的eval()函数可以将表达正确的简单计算的计算式字符串计算出结果,所以不用另外编写 “加(+)、减(-)、乘(*)、除(/)、整除(//)、求余(%)、乘方(**)” 这些计算的函数,直接将只含有这些计算的计算式输入eval()中就可以返回计算结果
如:122-100+50/10*108+2**2*2 就可以直接传入eval()进行计算
在 2 中,得到计算式拆分为列表后,遍历列表中的每个子字符串,如果发现其中有特殊运算,如:log,三角函数,阶乘、开根,就调用相关函数将其计算出来,并将结果替换在列表中相应的位置
# 如: ['122', '-', '100', '+', '50', '/', '10', '*', '108', '+', '2log4', '+', 'cos90', '+', '6!', '+', '2**2', '*', '2'] # 特殊计算处理后: ['122', '-', '100', '+', '50', '/', '10', '*', '108', '+', '2', '+', '0', '+', '720', '+', '2**2', '*', '2']3.3 调用eval()将特殊计算处理完成后的计算式进行最后计算
将特殊计算处理完成后的计算式列表连接成一个字符串,并传入eval()中,就可以得到结果:
# 特殊计算处理后的计算式列表
['122', '-', '100', '+', '50', '/', '10', '*', '108', '+', '2', '+', '0', '+', '720', '+', '2**2', '*', '2']
# 连接成字符串后
'122-100+50/10*108+2+0+720+2**2*2'
# 调用eval
print(eval('122-100+50/10*108+2+0+720+2**2*2'))
# 结果
1292.0
4.最后的计算
将 1 中计算式拆分后的列表,连接为一个字符串,并将字符串送入 3 中,经过 3.2 和 3.3 处理,便可以得到最后的结果
# 1中所得列表 ['122', '-100+50/10*', '108'] # 连接 '122-100+50/10*108' # 经过3.2和3.3处理和计算结果 562.0
源码 计算式字符串处理层(文件名:CalculatorDataConller.py)
import CalculatorCalculate as cal
# 用来处理界面传入的需要计算的表达式
class Controller:
# 先处理括号,式子中有括号,先计算括号中式子的值,再将计算结果替换式子中的括号部分
def processingData1(self, shizi):
# 用于存储去除括号后的拆分的式子列表。如果碰到括号就将式子分割,将括号前面部分放入列表,再计算括号中式子的值,最后将结果放在括号前面部分的后面
shizi_list = []
# 每次去除括号后,就重新进行一次括号检测,检测的式子为这次去除的括号的后面的式子
daiqie = str(shizi)
# 采用用一个死循环,检测括号,直到所有括号替换为数值,就可以结束死循环
while True:
# 遍历需要检测括号的式子中的每个字符
for i in range(len(daiqie)):
c = daiqie[i]
# 用于存储左括号前面的一部分式子
front_str = ""
# 用于存储左括号后面的一部分式子,用来查找右括号
back_str = ""
# 判断这个字符是不是左括号,
if c == '(':
# 如果左括号且不是在界面传入的计算式的第一位,就需要将左括号前面部分放入 shizi_list 列表
if i != 0:
front_str = daiqie[:i]
# 将左括号之前的一部分式子放入列表
shizi_list.append(front_str)
# 左括号后面的式子
back_str = daiqie[i + 1:]
# 遍历左括号后面的式子的每一个字符,寻找右括号
for k in range(len(back_str)):
j = back_str[k]
# 找到右括号,如果右括号不是式子的最后一个字符,就将括号中的式子计算出来,结果放入 shizi_list 列表
# 并且把右括号后面的式子放入 daiqie 变量,用于下一轮括号检测
if j == ')' and k != len(back_str) - 1:
# 括号中的式子
target = back_str[:k]
# 计算括号中的式子,并将结果放入 shizi_list 列表
shizi_list.append(self.processingData2(target))
# 右括号后面的式子
daiqie = back_str[k + 1:]
# 结束检测左括号后面式子中右括号的 for 循环
break
# 找到右括号,如果右括号是式子的最后一个字符,就将括号中的式子计算出来,结果放入 shizi_list 列表
# 并且把 daiqie 变量设为空字符串,用来标志括号已经全部处理完成,可以结束 while 死循环
elif j == ')' and k == len(back_str) - 1:
# 括号中的式子
target = back_str[:k]
# 计算括号中的式子,并将结果放入 shizi_list 列表
shizi_list.append(self.processingData2(target))
# 设置括号全部处理完成标志
daiqie = ""
# 结束检测左括号后面式子中右括号的 for 循环
break
# 右括号查找完成,表示一个括号处理完成,可以重新开始括号检测,检测后部分式子中的括号
break
# 如果待检测括号式子为空,表明括号处理完成,可以结束 while 死循环
if daiqie == "":
break
# 如果待检测括号式子中没有括号,也表明括号处理完成,就将式子添加到 shizi_list 表中,结束 while 死循环
elif '(' not in daiqie and ')' not in daiqie:
shizi_list.append(daiqie)
break
# 将处理好括号的计算式拆分的列表拼接成计算式
jisuanshi = ""
for i in shizi_list:
jisuanshi += str(i)
# 将没有没括号的式子,传入无括号式子处理的方法中,进行处理得到结果并返回
result = float(self.processingData2(jisuanshi))
return result
# 没有括号的计算式处理,将式子按基本符号(['+', '-', '*', '/', '%'])拆分开得到一个式子的拆分列表,并调用内部计算功能得到结果
# 其他运算符,如:**,//,log,√,cos,sin,tan,!,看作是特殊的运算符,这类符号需要将符号和符号作用的数字看作一个整体
def processingData2(self, basic_jisuanshi):
# 拆分计算式的标志
character = ['+', '-', '*', '/', '%']
num_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
# 存储式子拆分后的小字符串的列表
character_list = []
# 存储拆分标志后面的式子,在拆分过程中,这个字符串的长度必定会比传入的计算式长度越来越小,存在一定差值
# 差值为 character_list 中每个字符串长度之和
daiqie = basic_jisuanshi
# b是用来区别“*”与“**”,“/”与“//”,防止将“**”和“//”拆分
b = True
# 遍历无括号计算式中的每一个字符
for j in range(len(basic_jisuanshi)):
i = basic_jisuanshi[j]
# 如果这个字符是“*”或“/”,则需要判断是否是“**”或“//”;如果是特殊运算符,就不进行拆分,将b设置为False,直到碰到数字字符才将b设置为True
# 相当于加锁,碰到“**”和“//”就上锁,不进行拆分;直到循环走过这两个符号,就会遍历到数字字符,表明可以放开这把锁
if (i == '*' and basic_jisuanshi[j + 1] == '*') or (i == '/' and basic_jisuanshi[j + 1] == '/'):
b = False
elif i in num_list:
b = True
# 如果字符是拆分标志,并且没有被加锁,就可以进行拆分
if i in character:
if b:
# 如果需要进行拆分,那么拆分标识符号前面的必然是一个整体,用切片的方法进行分割,可以避免split带来的误切问题
# 拆分时,索引j为原计算式中的索引,与 daiqie 中需要切分的字符位置存在一定差值,故j需要减去这个差值,才能对应上在 daiqie
# 中需要切分的字符的位置
character_list.append(daiqie[:j - len(basic_jisuanshi) + len(daiqie)]) # 切割符前面的整体加入列表
# 切割符加入列表
character_list.append(i)
# 将需要切割的式子迭代为切割符后面的式子
daiqie = daiqie[j - len(basic_jisuanshi) + len(daiqie) + 1:]
# for循环执行完毕,说明对计算式的基本符号的分割完成,则 daiqie 中的结果是最后一次分割的分隔符后面的一个不需要再分割整体,故也需要加入列表
character_list.append(daiqie)
# 调用计算模块的计算功能进行计算,并将结果返回
calculator = cal.Calculating()
return calculator.calculating(character_list)
计算层(文件名:CalculatorCalculate.py)
import CalculatorSpecialCalculating as C
# 计算功能类
class Calculating:
# 需要传入的是一个列表,列表是一个计算式按基本运算符(['+', '-', '*', '/', '%'])分割出来的列表
def calculating(self, shiziliebiao):
# 遍历列表中每个元素,判断其中是否有特殊运算;如果有,调用特殊运算模块的相应运算函数,进行运算,并将结果替换列表中对应的特殊运算
for j in range(len(shiziliebiao)):
i = str(shiziliebiao[j])
if "log" in i:
shiziliebiao[j] = C.log(i)
elif '√' in i:
shiziliebiao[j] = C.kaigeng(i)
elif '!' in i:
shiziliebiao[j] = C.jiecheng(i)
elif 'cos' in i:
shiziliebiao[j] = C.cos(i)
elif 'sin' in i:
shiziliebiao[j] = C.sin(i)
elif 'tan' in i:
shiziliebiao[j] = C.tan(i)
# for 循环执行完成后,列表中一部分特殊运算经计算得出结果,另一部分特殊运算是eval()函数可以处理的计算
# 将列表中的所有字符串连成一个完整的计算式,传入eval()函数中,就可以得出结果
s = ""
for i in shiziliebiao:
s += str(i)
# 返回计算结果
return eval(s)
特殊计算处理层(文件名:CalculatorSpecialCalculating.py)
import math as m
# 对数,数据格式:底数log真数
def log(shizi):
dishuANDzhengshu = shizi.split('log', 1)
dishu = float(dishuANDzhengshu[0])
zhengshu = float(dishuANDzhengshu[1])
return m.log(zhengshu, dishu)
# 开平方,数据格式:√被开发数
def kaigeng(shizi):
gendishu = shizi[1:]
return eval(gendishu + "**0.5")
# 阶乘,数据格式:正整数!
def jiecheng(shizi):
return m.factorial(int(shizi[:-1]))
# 三角函数,接收数据的单位为:角度
def sin(shizi):
return m.sin(m.radians(float(shizi[3:])))
def cos(shizi):
return m.cos(m.radians(float(shizi[3:])))
def tan(shizi):
return m.tan(m.radians(float(shizi[3:])))
调用层(文件名:CalculatorInterface.py)
import CalculatorDataConller as cdc
def calculating(jisuanshi):
controller = cdc.Controller()
try:
result = controller.processingData1(jisuanshi)
except:
return "错误"
return result
# 测试
jisuanshi = '(2+6)*2+2log4+2**2+(2**2)**2-cos90+sin90+3!+3//2+50%40'
result = calculating(jisuanshi)
print(result) #结果 56
源码文件
只需要将文件拷贝到一个python项目的同一个文件夹下就可以使用
点击此处下载



