#!/usr/bin/python
#coding=utf-8
# 本程序由用户输入一个表达式字符串,然后计算这个表达式的值
# 表达式是一个四则运算表达式,可以包含^操作符
# 注意:乘方用^运算符,支持".3"这种表示小数的形式。负数需要用括号扩起来
# 思路:利用栈的方法,先将表达式从中缀表达式转换成后缀表达式,再进行计算
def isNum(value):
try:
value+1
except TypeError:
return False
else:
return True
def cal(strexpp):
''' 本函数由一个四则运算表达式字符串计算表达式的值
strexpr为一个四则运算表达式,如果这个表达式正确,则函数返回这个表达式的值,否则返回NULL'''
seqLegalChar=('+','-','*','/','(',')','^','1','2','3','4','5','6','7','8','9','0','.') #表达式中合法的字符集
seqOpr=seqLegalChar[0:7] #运算符序列
seqOpa=seqLegalChar[7:18] #操作数序列
# 表达式为空,则返回Null
if len(strexpp)==0: return Null
#去掉字符串中的空格
strexpr=strexpp.replace(' ','')
# 表达式包含不合法的支付,则返回Null
for ch in strexpr:
if ch not in seqLegalChar:
return Null
# 将表达式变成一个数字和符号的序列
numstart=-1 #标识数字的起始位置为numstart+1
seqExpr=[] #表达式序列
for i in range(0,len(strexpr)): #将表达式的数字和符号依次输出到序列
#本位置指向的是一个操作数,
if (strexpr[i] in seqOpa):
if numstart<0: #如果numstart小于0,使numstart指向本位置数字开始的地方
numstart=i
if i==len(strexpr)-1: #已读取到表达式最后一个字符,将数字转换后入列
seqExpr.append(float(strexpr[numstart:len(strexpp)]))
continue
#本次读取的字符是一个符号
if numstart>=0: #如果numstart大于0,则说明numstart与本位置之间是数字,需要提取数字。如果numstart==-1,则表明中间都是符号
seqExpr.append(float(strexpr[numstart:i])) #中间是数字,将数字转换后输出到序列
seqExpr.append(strexpr[i]) #将本次符号输出到序列
numstart=-1 #将numstart指针修改为本次位置
#将中缀表达式转换成为后缀表达式
seqPosfix=[] #后缀表达式序列,完成后seqPosfix中即为后缀表达式
stkOpra=[] #转换中所需要的符号栈
for op in seqExpr:
if isNum(op): #如果是数字,则直接输出到后缀表达式序列
seqPosfix.append(op)
continue
if not stkOpra: #如果符号栈为空,则直接压入第一个符号
stkOpra.append(op)
continue
if op ==')': #如果是')',需要匹配以前的'(',栈顶元素依次出栈输出,知道'('为止
while stkOpra[len(stkOpra)-1]!='(':
seqPosfix.append(stkOpra.pop()) #将'('弹出
stkOpra.pop()
elif op in ['+','-']: #如果是'+'或者'-',优先级最低
while (stkOpra and (stkOpra[len(stkOpra)-1]!='(')):
seqPosfix.append(stkOpra.pop())
stkOpra.append(op)
elif op in ['*','/']: #如果是'*','/',栈顶是'*','/','^'则弹出,否则入栈
while (stkOpra and (stkOpra[len(stkOpra)-1]=='^' )):
seqPosfix.append(stkOpra.pop())
stkOpra.append(op)
elif op in ['^','(']: #如果是'^'和'(',优先级最高,则直接入栈
stkOpra.append(op)
while stkOpra: #到最后如果符号栈不为空,则将符号栈的符号全部出栈
seqPosfix.append(stkOpra.pop())
#根据后缀表达式seqPosfix计算值
stkNumb=[] #装载操作数和值的栈
for op in seqPosfix:
if isNum(op):
stkNumb.append(op) #如果是数字,直接进栈
continue
p1=stkNumb.pop() #弹出两个操作数
p2=stkNumb.pop()
if op=='^': #根据运算符计算操作数的值
p=p2**p1
elif op=='*':
p=p2*p1
elif op=='/':
p=p2/p1
elif op=='+':
p=p2+p1
elif op=='-':
p=p2-p1
stkNumb.append(p) #将计算结果入栈
return stkNumb.pop() #最后的结果
expr=raw_input("请输入一个四则运算表达式(负数需要用括号扩起来,乘方用'^'运算符):")
res=cal(expr)
if not res:
print "你输入的四则运算表达式包含有不正确的字符,请检查后重新输入。"
else:
print "结果为:%f" % res