界面:
主程序:
from PyQt5.QtWidgets import (QWidget, QPushButton, QLineEdit,
QInputDialog, QApplication, QLabel)
from PyQt5 import QtGui
import os
import sys
import re
import isnum
import transformer
import get_result
import time
class Calculator(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.setWindowTitle('计算器')
#设置窗口的名称
self.setGeometry(100, 100, 480, 300)
#设置窗口的初始位置和初始大小self.setGeometry(x, y, 宽, 高)
self.num = ["0","1","2","3","4","5","6","7","8","9"]
self.option = ["+","-","*","÷"]
self.cos = ["√","sin","cos","tan"]
self.facto = ["²","!"]
self.power = "^"
self.left_parentha = "("
self.right_parentha = ")"
self.dot = "."
self.otpt = ""
self.show()
self.otptlist = []
self.mypath = os.path.abspath(os.path.dirname(__file__))+"/"+"history.txt"
self.newlis = []
def initUI(self):
self.btncal = QPushButton(self)
self.btncal.setText("=")
self.btncal.clicked.connect(self.calculteFunction)
self.btncal.move(20, 52)
self.label = QLabel("输入公式:",self)
self.label.move(30,22)
self.btncal.setFixedSize(80,25)
self.le = QLineEdit(self)
#self.le.setValidator(QtGui.setReadOnly()) #QDoubleValidator()
# 设置文本框只能录入数字,且不能通过键盘录入,只能通过点击下方的按钮来输入
# 录入数字之前要判断之前一个数字如果是0
# 那么后面输入的数字默认要覆盖这个0
# 如果后面要输入的是小数点那么默认不覆盖
self.le.setReadOnly(True)
self.le.setFixedSize(300,20)
self.le.setText("0")
self.le.move(130, 22)
self.le01 = QLineEdit(self)
self.le01.setFixedSize(300,20)
self.le01.move(130, 52)
self.le01.setReadOnly(True)
symbols = ["0","1","2","3","4","5","6","7","8","9","+","-","*","÷","²","^","√","!","sin","cos","tan",".","(",")"]
no = 0
y = 0
x = 0
while no < len(symbols)and x < 5:
self.btn=QPushButton(symbols[no],self)
self.btn.move(20+90*x,80+30*y)
self.btn.clicked.connect(self.calculteFunction)
if x == 4:
x = 0
y += 1
else:
x += 1
no += 1
self.resetbtn = QPushButton(self)
self.resetbtn.setText("清空")
self.resetbtn.move(380, 200)
self.resetbtn.clicked.connect(self.reset_text)
self.backspacebtn = QPushButton(self)
self.backspacebtn.setText("退格")
self.backspacebtn.move(380, 230)
self.backspacebtn.clicked.connect(self.delete_the_end_simbol)
def calculteFunction(self):
# 规范输入公式
sym=self.sender().text()
sym_original = self.le.text()
self.le01.setText("")
#每次在文本框传输内容之前,对点击的按钮进行判断
if sym != "=":
if sym in self.num:
#如果点击的是数字
if sym_original[-1] == self.right_parentha:
#如果前面是右括号那么不可以添加
self.otpt = sym_original
self.le.setText(self.otpt)
elif sym_original[-1] == "0":
if len(sym_original) == 1 or sym_original[-2] in ["+","-","*","÷","²","^","√","sin","cos","tan","("]:
#如果前面是0,那么要对0之前的哪一位再判断,如果0的前面是["+","-","x","÷","²","^","√","sin","cos","tan","("]那么就将0删除再添加
new_sym_original = sym_original[:-1]
self.otpt = new_sym_original+sym
self.otptlist.append(sym)
self.le.setText(self.otpt)
else:#如果0的前面不是["+","-","x","÷","²","^","√","sin","cos","tan","("]那么就可以接在后面添加
self.otpt = sym_original+sym
self.otptlist.append(sym)
self.le.setText(self.otpt)
else:#排除上面的情况之后,其他的情况可以接在后面添加
self.otpt = sym_original+sym
self.otptlist.append(sym)
self.le.setText(self.otpt)
elif sym in self.option:
#如果点击的字符在["+","-","x","÷"]范围
if len(sym_original) == 0 or sym_original[-1] in ["+","-","*","÷","^","√","n","s",".","("]:#["+","-","*","÷","^","√","sin","cos","tan",".","("]
#那么如果前面没有任何字符或者前面的字符在["+","-","x","÷","^","√","sin","cos","tan",".","("]里面,那么这个被点击的字符就不能被录入:
self.otpt = sym_original
self.le.setText(self.otpt)
else:
self.otpt = sym_original+sym
self.otptlist.append(sym)
self.le.setText(self.otpt)
elif sym in self.cos:
#如果点击的字符在["√","sin","cos","tan"]范围
if len(sym_original) == 0 or sym_original[-1] in ["+","-","*","÷","(","√"]:
#如果前面为空或者前面的字符在["+","-","x","÷","(","√"]范围就可以直接在后面加上点击的字符
self.otpt = sym_original+sym
self.otptlist.append(sym)
self.le.setText(self.otpt)
elif sym_original[-1] == "0":
if len(sym_original) == 1 or sym_original[-2] in ["+","-","*","÷","²","^","√","sin","cos","tan","("]:
#如果前面是0,那么要对0之前的哪一位再判断,如果0的前面是["+","-","x","÷","²","^","√","sin","cos","tan","("]那么就将0删除再添加
new_sym_original = sym_original[:-1]
self.otpt = new_sym_original+sym
self.otptlist.append(sym)
self.le.setText(self.otpt)
else:#如果0的前面不是["+","-","x","÷","²","^","√","sin","cos","tan","("]那么就可以接在后面添加
self.otpt = sym_original+sym
self.otptlist.append(sym)
self.le.setText(self.otpt)
else:
#如果不是上面的情况那么就添加不了
self.otpt = sym_original
self.le.setText(self.otpt)
elif sym in self.facto or sym == self.power or sym == self.dot:
#如果点击的字符为"²","!","^","."
if len(sym_original) != 0:
#如果前面为不为空
if sym_original[-1] in ["0","1","2","3","4","5","6","7","8","9",")"]:
#如果前面一个字符在["0","1","2","3","4","5","6","7","8","9",")"]范围,那么就可以直接在后面添加
self.otpt = sym_original+sym
self.otptlist.append(sym)
self.le.setText(self.otpt)
else:
#如果不是上面的情况那么就添加不了
self.otpt = sym_original
self.le.setText(self.otpt)
else:
#如果前面为空那么就添加不了
self.otpt = sym_original
self.le.setText(self.otpt)
elif sym == self.left_parentha:
#如果点击的是左括号(
if len(sym_original) == 0 or sym_original[-1] in ["+","-","*","÷","^","√","n","s","("]:#["+","-","*","÷","^","√","sin","cos","tan","("]
#如果前面为空,或者前面一个字符在["+","-","x","÷","^","√","sin","cos","tan","("]范围,那么就可以直接在后面添加
self.otpt = sym_original+sym
self.otptlist.append(sym)
self.le.setText(self.otpt)
elif sym_original[-1] == "0":
if len(sym_original) == 1 or sym_original[-2] in ["+","-","*","÷","²","^","√","sin","cos","tan","("]:
#如果前面是0,那么要对0之前的哪一位再判断,如果0的前面是["+","-","x","÷","²","^","√","sin","cos","tan","("]那么就将0删除再添加
new_sym_original = sym_original[:-1]
self.otpt = new_sym_original+sym
self.otptlist.append(sym)
self.le.setText(self.otpt)
else:#如果0的前面不是["+","-","x","÷","²","^","√","sin","cos","tan","("]那么就可以接在后面添加
self.otpt = sym_original+sym
self.otptlist.append(sym)
self.le.setText(self.otpt)
else:
#如果不是上面的情况那么就添加不了
self.otpt = sym_original
self.le.setText(self.otpt)
elif sym == self.right_parentha:
#如果点击的是右括号,那么必须要判断前面是否有匹配的左括号
if self.check_parentha(sym_original) >0 and len(sym_original) != 0 and sym_original[-1] in ["0","1","2","3","4","5","6","7","8","9","²","!",")"]:
#如果同时满足前面有左括号匹配,且前面不为空,且前面一个字符属于["0","1","2","3","4","5","6","7","8","9","²","!",")"]那么就可以录入这个右括号
self.otpt = sym_original+sym
self.otptlist.append(sym)
self.le.setText(self.otpt)
else:
self.otpt = sym_original
self.le.setText(self.otpt)
else:
print("这个情况没有考虑")
else:
#对点击字符是“=”的情况进行判断
if self.check_parentha(sym_original) >0 and sym_original[-1] in ["0","1","2","3","4","5","6","7","8","9","²","!",")"]:
#如果发现有未被比配的左括号,那么就将对应的右括号先补上,再执行计算
self.otpt = sym_original+")"*self.check_parentha(sym_original)
self.le.setText(self.otpt)
for i in range(self.check_parentha(sym_original)):
self.otptlist.append(")")#*self.check_parentha(sym_original)
self.get_info_from_input()
#self.check_formula()
elif self.check_parentha(sym_original) == 0 and sym_original[-1] in ["0","1","2","3","4","5","6","7","8","9","²","!",")"]:
#如果没有未匹配的左括号,那么就执行计算
self.otpt = sym_original
self.le.setText(self.otpt)
self.get_info_from_input()
#self.check_formula()
elif sym_original[-1] not in ["0","1","2","3","4","5","6","7","8","9","²","!",")"]:
#如果公式没有输入完整那么提示表达公式有误
self.otpt = sym_original
self.le.setText(self.otpt)
self.le01.setText("表达公式有误!")
else:
print("这个情况没有考虑。。。")
#self.otptlist = self.otpt
#print("正在计算")
#print(self.otptlist)
def get_info_from_input(self):
#1.处理文本框的信息,整合数字项
print(self.otptlist)
num_sample = ""
self.newlis = []
i = 0
length = len(self.otptlist)
while i < length:
if isnum.isDecimalOrInt(self.otptlist[i]) or self.otptlist[i] == ".": #isnum.isDecimalOrInt(self.otptlist[i])
num_sample += self.otptlist[i]
else:
if num_sample != "":
self.newlis.append(num_sample)
num_sample = ""
self.newlis.append(self.otptlist[i])
if i == length-1:
if num_sample != "":
self.newlis.append(num_sample)
i+=1
current_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
with open(self.mypath,"a",encoding='utf-8') as f: # r"E:\file\python test files\2020.5\计算器升级1.0\caloutput.txt"
f.write(current_time+":"+str(self.newlis))
f.write("\r\n")
f.close()
#2. 将列表转换为后缀表达式的格式
self.Transform_expression(self.newlis)
def reset_text(self):
self.le.setText("0")
self.le01.setText("")
self.otpt = ""
self.otptlist = []
def check_parentha(self,str):
left_t = re.findall(r"\(",str)
right_t = re.findall(r"\)",str)
difference = len(left_t) - len(right_t)
return difference
def Transform_expression(self,newlis):
#计算
back_lis = transformer.ChangeExpression(newlis)
#print(back_lis)
#print(type(back_lis))
str_to_num = get_result.TransformStrToFloat(back_lis)
result = get_result.Calculate(str_to_num)
self.le01.setText(str(result))
def delete_the_end_simbol(self):
if len(self.otptlist)>1:
self.otptlist.pop()
self.otpt = ""
for i in self.otptlist:
self.otpt+=i
self.le.setText(self.otpt)
else:
self.le.setText("0")
self.le01.setText("")
self.otpt = ""
self.otptlist = []
app = QApplication(sys.argv)
ex = Calculator()
ex.show()
sys.exit(app.exec_())
isnum.py
import re
lis = ['06', '+', '(', '0.0.9', '÷', '2', '+', '3.2', ')', '*', '5','4.30','0.4','007.8']
# 判断字符串是否是小数或者整数
def isDecimalOrInt(s):
#去除字符串两边的空格
s= s.strip()
flag = True
#判断是否是整数
intRet=re.match("^[0-9]+$",s)
#判断是否是小数
decRet= re.match("^\d+\.\d+$",s)
#如果是整数
if intRet:
if len(s)>1 and s[0]=="0":
#如果整数的长度大于1,那么判断其首位是否为0,如果为零返回false
flag = False
return flag
elif decRet:
pos = s.index(".")
if pos!=1 and s[0]=="0":
flag = False
return flag
else:
flag = False
return flag
return flag
operation.py
import math
def Calc_Add_Minus_Multi_Dvide_Pow(num1, num2,sign):
if sign == '+':
return num1+num2
elif sign == '-':
return num2-num1
elif sign == '*':
return num2*num1
elif sign == '÷':
return num2/num1
else:
#sign == '^'
return num2**num1
def Calc_Sin_Cos_Tan_Sqr_Sqrr(num,sign):
if sign == 'sin':
return math.sin(num)
elif sign == 'cos':
return math.cos(num)
elif sign == 'tan':
return math.tan(num)
elif sign == '√':
return num**0.5
elif sign == '²':
return num**2
else:# '!'
i = 1
res = 1
while i<=num:
res *= i
i+=1
return res
transformer.py
import isnum
import os
import time
def ChangeExpression(s):
operators = ['+', '÷', '-', '*', 'sin', 'cos', 'tan', '√', '²', '^', '!']
operator_grade = {
'^':4,'²':4,'!':4,'sin':3,'cos':3,'tan':3,'√':3,'÷':2,'*':2,'+':1,'-':1}
paranthes = ['(', ')']
stack = []
numlist = []
current_path = os.path.abspath(os.path.dirname(__file__))+"/"+"history_transforemed_expression.txt"
current_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
for i in s:
#print(stack,":",numlist)
if isnum.isDecimalOrInt(i):
#如果是数字直接加入表达式存储栈numlist
numlist.append(i)
elif i in operators:
#如果是操作符,那么以下情况处理
if len(stack)==0:
#如果符号存储栈stack为空,那么直接将扫描到的符号添加到符号存储栈stack中
stack.append(i)
elif stack[-1] in operators:
#如果栈顶是操作符,那么以下情况处理
if operator_grade[stack[-1]]<operator_grade[i]:
#如果扫描到的操作符优先级大于栈顶操作符的优先级,那么直接将扫描到的符号添加到存储栈stack中
stack.append(i)
# elif operator_grade[stack[-1]]>operator_grade[i] and stack[-1] in operator_angle:
else:
#如果扫描到的操作符优先级不大于栈顶操作符的优先级,那么将stack栈顶的操作符弹出并追加到表达式存储栈numlist中,直到遇到优先级小的操作符或者stack为空
while len(stack)>0 and stack[-1] in operators and operator_grade[stack[-1]] >= operator_grade[i]:
numlist.append(stack.pop())
stack.append(i)
else:
#如果扫描到的是“(”,(这里的else在排除上述可能之后只剩下“(”这种情况,那么直接将扫描到的符号追加到符号存储栈stack中
stack.append(i)
elif i == '(':
#如果扫描到的操作符是‘(’,那么直接将扫描到的操作符添加到stack中
stack.append(i)
else:
#如果扫描到的是‘)’,那么丢弃,然后按一下情况处理
# if stack[-1] == '(':
#如果stack栈顶是’(‘,那么将(弹出,此时一对括号以及原本之间的操作符已经处理完毕
#stack.pop()
while len(stack)>0 and stack[-1]!='(':
#当stack栈顶不是‘(’时,将符号栈stack中的符号依次弹出并追加到numlist栈中
numlist.append(stack.pop())
if len(stack)>0 and stack[-1] == '(':
#如果stack栈顶是’(‘,那么将(弹出,此时一对括号以及原本之间的操作符已经处理完毕
stack.pop()
# if stack[-1] in operator_angle:
# numlist.append(stack.pop())
while len(stack)>0:
#如果stack栈不为空,(此时所有的括号被丢弃,如果还有内容,只能是操作符),那么将stack中的操作符依次弹出并追加到numlist中
numlist.append(stack.pop())
print(numlist)
with open(current_path,"a",encoding='utf-8') as f:
f.write(current_time+":"+str(numlist))
f.write("\r\n")
f.close()
return numlist
if __name__ == "__main__":
s = ['6', '+', '(', '7', '÷', '2', '+', '3', ')', '*', '5']
s3 = ['12', '+', '6', '*', '2', '-', '9', '÷', '3', '-', '8']
s4 = ['6', '*', '7', '+', '8', '-', '7', '÷', '(', '6', '+', '2', ')']
s5 = ['7', '*', '(', '8', '+', '89', ')', '-', '7', '÷', '(', '(', '8', '-', '1', ')', '*', '2', ')']
s6 = ['(', '1', '*', '7', '+', '8', '-', '5', '*', '2', ')', '÷', '3', '+', '5', '*', '(', '(', '(', '7', '+', '8', ')', '*', '2', '-', '7', ')', '÷', '3', ')']
s7 = ['7', '÷', '1', '+', '2', '*', '(', '8', '-', '9', '÷', '3', '+', '6', '*', '3', ')', '+', '(', '(', '7', '-', '6', ')', '÷', '8', '+', '10', '-', '3', '*', '2', ')', '+', '60', '-', '20', '*', '2']
s8 = ['(', '(', '7', '-', '5', ')', '*', '8', '+', '6', ')', '*', '6', '-', '8', '÷', '(', '7', '+', '8', '-', '9', '*', '2', ')', '*', '2', '-', '8', '÷', '2']
s10 = ['(', '7', '+', '1', ')', '^', '2', '+', 'sin', '(', '8', '+', '9', ')', '²', '+', '√', '(', '9', '+', '8', ')', '-', '6', '!']
s11 = ['6', '²', '+', '(', '7', '+', '8', ')', '²', '+', 'tan', '(', '78', '+', '6.5', ')', '+', '(', '50', '+', '6', ')', '!', '*', '6', '^', '3', '*', '√', '8', '²', '+', '(', '8', '*', '5', '!', ')', '^', '2', '÷', '2']
s12 = ['sin','(', '3', '+', '5', ')', '^', '7', '+', '6', '*', '3']
s13 = ['sin','(', '3', '+', '5', ')', '^', '7']
s14 = ['2','*','(', '3', '+', '5', ')', '÷', '7']
s15 = ['6', '-', '2', '*', '(', '3', '+', '7', ')', '÷', '3']
s16 = ['sin', '(', '70', '*', '2', '-', '9', '²', '+', '2', '^', '2', ')', '+', '7', '!', '+', '(', '3', '+', '1', ')', '!', '-', 'cos', '(', '9', '-', '6', ')']
s17 = ['12', '÷', '(', '6', '*', '2', '-', '5', '+', '8', '*', '(', '7', '-', '2', ')', ')']
ChangeExpression(s6)
#print(isnum.isDecimalOrInt('²'))
get_result.py
import math
import isnum
import operation
s1 = ['70', '2', '*', '9', '²', '-', '2', '2', '^', '+', 'sin', '7', '!', '+', '3', '1', '+', '!', '+', '9', '6', '-', 'cos', '-']
s2 = ['12', '6', '2', '*', '5', '-', '8', '7', '2', '-', '*', '+', '÷']
s3 = ['6', '²', '7', '8', '+', '²', '+', '78', '6.5', '+', 'tan', '+', '1', '6', '+', '!', '2', '3', '^', '*', '8', '²', '√', '*', '+', '8', '5', '!', '*', '2', '^', '2', '÷', '+']
s4 = ['7', '1', '+', '2', '^', '8', '9', '+', '²', 'sin', '+', '9', '8', '+', '√', '+', '6', '!', '-']
#['(', '(', '7', '-', '5', ')', '*', '8', '+', '6', ')', '*', '6', '-', '8', '÷', '(', '7', '+', '8', '-', '9', '*', '2', ')', '*', '2', '-', '8', '÷', '2']:
s5 = ['7', '5', '-', '8', '*', '6', '+', '6', '*', '8', '7', '8', '+', '9', '2', '*', '-', '÷', '2', '*', '-', '8', '2', '÷', '-']
#['7', '÷', '1', '+', '2', '*', '(', '8', '-', '9', '÷', '3', '+', '6', '*', '3', ')', '+', '(', '(', '7', '-', '6', ')', '÷', '8', '+', '10', '-', '3', '*', '2', ')', '+', '60', '-', '20', '*', '2']:
s6 = ['7', '1', '÷', '2', '8', '9', '3', '÷', '-', '6', '3', '*', '+', '*', '+', '7', '6', '-', '8', '÷', '10', '+', '3', '2', '*', '-', '+', '60', '+', '20', '2', '*', '-'];
#['6', '+', '(', '7', '÷', '2', '+', '3', ')', '*', '5']:
s7 = ['6', '7', '2', '÷', '3', '+', '5', '*', '+'];
#['7', '*', '(', '8', '+', '89', ')', '-', '7', '÷', '(', '(', '8', '-', '1', ')', '*', '2', ')']:
s8 = ['7', '8', '89', '+', '*', '7', '8', '1', '-', '2', '*', '÷', '-'];
#['(', '1', '*', '7', '+', '8', '-', '5', '*', '2', ')', '÷', '3', '+', '5', '*', '(', '(', '(', '7', '+', '8', ')', '*', '2', '-', '7', ')', '÷', '3', ')']:
s9 = ['1', '7', '*', '8', '+', '5', '2', '*', '-', '3', '÷', '5', '7', '8', '+', '2', '*', '7', '-', '3', '÷', '*', '+'];
s = ['7', '5', '-', '8', '*', '6', '+', '6', '*', '8', '7', '8', '+', '9', '2', '*', '-', '÷', '2', '*', '-', '8', '2', '÷', '-']
#operators = ['+', '÷', '-', '*', '^', 'sin', 'cos', 'tan', '√', '²', '^', '!']
#operator_grade = {'^':4,'²':4,'!':4,'sin':3,'cos':3,'tan':3,'√':3,'÷':2,'*':2,'+':1,'-':1}
# print(float("5.2232 "))
def Calculate(s):
opt1 = [ '+', '÷', '-', '*', '^']
opt2 = ['sin', 'cos', 'tan', '√', '²', '^', '!']
temp = []
for i in s:
if isinstance(i,float):
temp.append(i)
print("temp1:",temp)
elif i in opt1:
if isinstance(temp[-1],float) or isinstance(temp[-1],int) :
num1 = temp.pop()
num2 = temp.pop()
r = operation.Calc_Add_Minus_Multi_Dvide_Pow(num1, num2,i)
temp.append(r)
else:
temp.append(i)
print("temp2:",temp)
else:
if isinstance(temp[-1],float) or isinstance(temp[-1],int):
num = temp.pop()
r = operation.Calc_Sin_Cos_Tan_Sqr_Sqrr(num,i)
temp.append(r)
else:
temp.append(i)
print("temp3:",temp)
#print(len(temp))
if len(temp)>1:
print("递归")
Calculate(temp)
else:
print(temp[-1])
return temp[-1]
def TransformStrToFloat(s):
newlist = []
for i in s:
if isnum.isDecimalOrInt(i):
n = float(i)
newlist.append(n)
else:
newlist.append(i)
return newlist
if __name__ == "__main__":
lis = TransformStrToFloat(s3)
Calculate(lis)