利用python开发一个简单的计算器:
1. 实现加减乘除和括号的优先级解析
2. 根据用户输入的表达式,例如(1+(2*(8-2)/3.0-4),返回该表达式的结果。
方法一:栈
#coding=utf-8 #calculate the value of expersion import sys import re import pdb OPER = '(+-*/' CHR_NUM = '0123456789.' def welcome_func(): ''' 输出欢迎信息,读取算术表达式,并做简单处理 ''' welcome_str = 'Useful calculator!' print '-'*10, welcome_str, '-'*10 while True: exp = raw_input('Input the expression:(enter q to exit) ').strip() if exp == 'q': sys.exit(0) elif len(exp) == 0: continue else: #对表达式进行规范化处理 if not exp.startswith('(') or not exp.endswith(')'): exp = '(' + exp + ')' exp = re.sub('\s*', '',exp) #解析表达式中每一个独立元素,并将其放入一个列表中 i = 0 exp_list = [] while i < len(exp): item = exp[i] j = i+1 if item in CHR_NUM: while j < len(exp) and exp[j] in CHR_NUM: item += exp[j] j += 1 #special!! 处理负数 elif item == '-' and exp[i-1] in OPER: while j < len(exp) and exp[j] in CHR_NUM: item += exp[j] j += 1 exp_list.append(item) i = j #将exp_list传给cal_exp函数进行求值计算 #pdb.set_trace() print exp, '=', cal_exp(exp_list) def cal_exp(s): ''' 利用栈的方式对表达式进行单元计算,每一个对小括号看作一个计算单元 :param s: 表达式列表 :return: 返回表达式的值 ''' Sd = [] #存放操作数的栈 So = [] #存放操作符的栈 L = len(s) for i in range(L): #计算最里层小括号中简单表达式的值并将其放入操作数栈Sd中 if s[i] == ')': r = [] r.insert(0, Sd.pop()) t = So.pop() while t != '(': r.insert(0, t) r.insert(0, Sd.pop()) t = So.pop() #计算简单表达式 res = cal_simple(r) Sd.append(res) #将操作符放入So中 elif s[i] in OPER: So.append(s[i]) #将操作数放入Sd中 else: Sd.append(s[i]) return float(Sd[0]) def cal_simple(r): ''' 对简单表达式求值 两层计算:先计算乘除后计算加减 :param r: 简单表达式列表 :return: 返回简单表示的值 ''' while '*' in r or '/' in r: R = r for k in range(len(r)-1): if r[k] in '*/': break else: continue R = [r[i] for i in range(len(r)) if i not in [k-1, k, k+1]] if r[k] == '*': R.insert(k-1, str(float(r[k-1]) * float(r[k+1]))) if r[k] == '/': R.insert(k-1, str(float(r[k-1]) / float(r[k+1]))) r = R while '+' in r or '-' in r: R = r for k in range(len(r)-1): if r[k] in '+-': break else: continue R = [r[i] for i in range(len(r)) if i not in [k-1, k, k+1]] if r[k] == '+': R.insert(k-1, str(float(r[k-1]) + float(r[k+1]))) if r[k] == '-': R.insert(k-1, str(float(r[k-1]) - float(r[k+1]))) r = R return str(r[0]) if __name__ == '__main__': welcome_func()
测试结果如下:
方法二:正则表达式
#coding=utf-8 import sys import re import pdb def welcome_func(): ''' 输入判断 ''' welcome_str = 'Super calculator!' print '-'*10, welcome_str, '-'*10 while True: iput = raw_input('Input your expression:(q to exit.) ') if iput == 'q': sys.exit(0) elif len(iput) == 0: continue else: iput = re.sub('\s*', '', iput) return iput def mul_div(exp): ''' 乘除运算 ''' data = re.search('\d+\.*\d*[\*\/]+[\+\-]?\d+\.*\d*', exp) if not data: return exp data = data.group() if len(data.split('*')) > 1: d1 , d2 = data.split('*') value = float(d1) * float(d2) else: d1 , d2 = data.split('/') if float(d2) == 0.0: sys.exit('Dividend is zero!') value = float(d1) / float(d2) s1 , s2 = exp.split(data) new_exp = '%s%s%s' % (s1, value, s2) return mul_div(new_exp) def add_sub(exp): ''' 加减运算 ''' exp = exp.replace('+-', '-') exp = exp.replace('--', '+') exp = exp.replace('-+', '-') exp = exp.replace('++', '+') data = re.search('[\+\-]?\d+\.*\d*[\+\-]{1}\d+\.*\d*', exp) if not data: return exp data = data.group() if len(data.split('+')) > 1: d1, d2 = data.split('+') value = float(d1) + float(d2) elif data.startswith('-'): d1, d2, d3 = data.split('-') value = -float(d2) - float(d3) else: d1, d2 = data.split('-') value = float(d1) - float(d2) s1, s2 = exp.split(data) new_exp = '%s%s%s' % (s1, value, s2) return add_sub(new_exp) def del_bracket(exp): ''' 小括号去除运算 ''' #pdb.set_trace() if not re.search(r'\(([^()]+)\)', exp): ret1 = mul_div(exp) ret2 = add_sub(ret1) return ret2 data = re.search(r'\(([^()]+)\)', exp).group() simple = data.strip('[\(\)]') ret1 = mul_div(simple) ret2 = add_sub(ret1) s1, s2 = exp.split(data) new_exp = '%s%s%s' % (s1, ret2, s2) return del_bracket(new_exp) if __name__ == '__main__': expression = welcome_func() ret = del_bracket(expression) print expression, '=', ret
该方法利用正则表达式匹配最高优先级的表达式(最里层小括号中的表达式),将计算得到的值替换该表达式,并利用递归的思想最终完成整个表达式的计算。
注:欢迎批评指正!