Python之计算器

作业:

     使用正则表达式和递归实现计算器功能。

 实现:

       1、实现带括号的计算

       2、实现指数、加减乘除求余取整等功能


1、实现思路

  1.1 先查找括号,有括号则递归计算括号内的结果。无括号则直接计算表达式

  1.2 使用正则表达式匹配字符串,用计算结果替换计算的表达式。

2、流程图

 

3、测试效果

  计算器对于测试输入做了校验。比如输入 '-2 - / 3' 、 '2 + * 3' 、 '-3 +-' 等等

 

4、源码实现

  1 #!/usr/bin/env python3
  2 # -*- coding:utf-8 -*-
  3 # Version:Python3.5.0
  4 import re
  5 
  6 def check_exp(get_input):
  7     '''
  8     输入一个表达式,判断是否正确,返回一个去空格的表达式
  9     :param get_input: 获取的表达式
 10     :return: 返回一个去空格的表达式
 11     '''
 12     char_set = set(('0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
 13                     '+', '-', '*', '/', '%', '//', '**', '.', '(', ')'))       # 有效表达式的字符集合
 14     # 判断输入的字符合法,输入的表达式字符属于全集char_set为真
 15     if set(get_input).issubset(char_set):
 16         # 输入的表达式是乘号'*'、除号'/',百分号'%' 开头的,不合法
 17         if get_input.startswith('*') or get_input.startswith('/') or get_input.startswith('%'):
 18             print('\033[31;1m输入的表达式不正确,请重新输入!\033[0m')
 19             return False
 20         # 输入的表达式是乘号'*'、除号'/',百分号'%'、加号'+'、减号'-' 结尾的,不合法
 21         elif (get_input.endswith('*') or get_input.endswith('/') or get_input.endswith('%')
 22                 or get_input.endswith('+') or get_input.endswith('-')):
 23             print('\033[31;1m输入的表达式不正确,请重新输入!\033[0m')
 24             return False
 25         # 输入的表达式中,有两个点号或者加减号后面跟着乘除百分号的,不合法
 26         elif ('..' in get_input or '+*' in get_input or '+/' in get_input or '+%' in get_input
 27                 or '-*' in get_input or '-/' in get_input or '-%' in get_input):
 28             print('\033[31;1m输入的表达式不正确,请重新输入!\033[0m')
 29             return False
 30         else:
 31             return True
 32     else:
 33         print('\033[31;1m输入的表达式包涵其他字符,无法进行计算,请重新输入!\033[0m')
 34         return False
 35 
 36 def replace_symbol(exp):
 37     '''
 38     化简表达式,比如“++-”转换成“-",返回最简表达式
 39     :param exp: 需要化简的表达式
 40     :return:    化简后的表达式
 41     '''
 42     # 初始化一个替换字符的列表
 43     replace_char_list = [('+-', '-'), ('-+', '-'), ('++', '+'), ('--', '+'), ('*+', '*'),
 44                         ('/+', '/'), ('%+', '%'), ('//+', '//'), ('**+', '**')]
 45     flag = False    # 初始化标识符
 46     count = 0       # 初始化不匹配次数
 47     while not flag:
 48         for i in replace_char_list:
 49             if i[0] in exp:    # 要化简的字符在表达式中,则直接替换
 50                 exp = exp.replace(i[0], i[1])   # 把需要替换的键字符串修改为其值的字符串
 51                 break     # 中断for循环,进行下一次while循环
 52             else:
 53                 count += 1
 54             # 当count等于 len(replace_char_list)时,即 没有需要替换的字符了,退出循环
 55             if count == len(replace_char_list):
 56                 flag = True
 57 
 58         if exp.startswith('+'):
 59             exp = exp[1:]   # 除去表达式中开头的加号
 60     return exp
 61 
 62 def parenthesis(exp):
 63     '''
 64     运算括号里面的表达式,运算结果替代括号的内容,返回运算结果
 65     :param exp: 计算的表达式
 66     :return: None
 67     '''
 68     match = re.search('\(([\+\-\*\/%\/\/\*\*]*\d+\.*\d*){2,}\)', exp)  # 匹配括号内的表达式
 69     if match:   # 找到匹配的字符
 70         content = match.group()[1:-1]     # 获取匹配到的表达式,并过滤括号
 71         result = calculate(content)     # 调用计算函数,返回结束结果
 72         print('计算前的表达式:\033[32;1m%s\033[0m' % exp)
 73         print('括号中运算结果:\033[33;1m%s=%s\033[0m' % (content, result))
 74         replace_content = '(' + content + ')'
 75         exp = exp.replace(replace_content, result)      # 把运算结果替换表达式
 76         exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
 77         print('计算后的表达式:\033[34;1m%s\033[0m\n' % exp)
 78         parenthesis(exp)     # 递归执行括号处理
 79     else:
 80         result = calculate(exp)  # 当表达式没有括号时,直接计算表达式结果
 81         print('表达式运算结果:\033[35;1m%s\033[0m' % result)
 82 
 83 def power(exp):
 84     '''
 85     幂运算,返回运算结果
 86     :param exp: 幂运算的表达式
 87     :return: 计算后的表达式
 88     '''
 89     match = re.search('\d+\.?\d*[\*]{2}[\+\-]*\d+\.?\d*', exp)  # 匹配幂运算
 90     if match:   # 找到匹配的字符
 91         content = match.group()     # 获取匹配到的表达式
 92         if len(content.split('**')) > 1:
 93             n1, n2 = content.split('**')
 94             value = float(n1) ** float(n2)
 95             exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
 96             exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
 97             return power(exp)      # 递归重复匹配
 98         else:
 99             pass
100     else:
101         return exp  # 不匹配到,返回exp
102 
103 def mul_div(exp):
104     '''
105     做乘法、除法、取余、取整运算,返回运算结果
106     :param exp: 乘法、除法、取余、取整运算的表达式
107     :return: 计算后的表达式
108     '''
109     match = re.search('\d+\.?\d*[\*\/%\/\/]+[\+\-]?\d+\.?\d*', exp)  # 匹配乘、除、取余、取整运算
110     if match:   # 找到匹配的字符
111         content = match.group()     # 获取匹配到的表达式
112         if len(content.split('*')) > 1:
113             n1, n2 = content.split('*')
114             value = float(n1) * float(n2)   # 乘法运算
115             exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
116             exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
117             return mul_div(exp)
118 
119         elif len(content.split('//')) > 1:
120             n1, n2 = content.split('//')     # 取余运算
121             value = float(n1) // float(n2)
122             exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
123             exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
124             return mul_div(exp)
125 
126         elif len(content.split('%')) > 1:
127             n1, n2 = content.split('%')     # 除法运算
128             value = float(n1) % float(n2)
129             exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
130             exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
131             return mul_div(exp)
132 
133         elif len(content.split('/')) > 1:
134             n1, n2 = content.split('/')    # 取整运算
135             value = float(n1) / float(n2)
136             exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
137             exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
138             return mul_div(exp)
139 
140         else:
141             pass
142     else:
143         return exp  # 不匹配到,返回exp
144 
145 def add_sub(exp):
146     '''
147     加法、减法运算,返回运算结果
148     :param exp: 加法、减法运算的表达式
149     :return: 计算后的表达式
150     '''
151     match = re.search('\-?\d+\.?\d*[\+\-]+\d+\.?\d*', exp)  # 匹配加法、减法
152     if match:   # 找到匹配的字符
153         content = match.group()     # 获取匹配到的表达式
154         if len(content.split('+')) > 1:
155             n1, n2 = content.split('+')
156             value = float(n1) + float(n2)
157             exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
158             exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
159             return add_sub(exp)
160 
161         elif len(content.split('-')) > 1:
162             if len(content.split('-')) == 3:    # 被减数是负数的情况
163                 n1, n2 = content.split('-')[1:]     #  过滤分割列表开头的空白字符串
164                 value = float('-' + n1) - float(n2)   # 被减数需要添加一个负号
165                 exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
166                 exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
167                 return add_sub(exp)
168             elif len(content.split('-')) == 2:    # 被减数是正数的情况
169                 n1, n2 = content.split('-')     #  直接把两个操作数赋值给对应的变量
170                 value = float(n1) - float(n2)   # 做减法运算
171                 exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
172                 exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
173                 return add_sub(exp)
174             else:
175                 pass
176         else:
177             pass
178     else:
179         return exp  # 不匹配到,返回exp
180 
181 def calculate(exp):
182     '''
183     获取一个运算表达式,返回运算结果
184     :param exp: 表达式
185     :return: 运算结果
186     '''
187     result = power(exp)         # 执行幂运算,返回运算结果
188     result = mul_div(result)    # 执行乘法、除法、取余、取整运算,返回运算结果
189     result = add_sub(result)    # 执行加法、减法运算,返回运算结果
190     return result
191 
192 if __name__ == '__main__':
193     print('\033[31;1m欢迎使用计算器\033[0m'.center(100,'='))
194     while True:
195         # 计算 s = '1-2 *(   (60- 30+(-40.0/5)*(9-2*5 / 3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'
196         get_input = input('\n\033[32;1m请输入一个表达式 | 退出(q): \033[0m').strip()
197         get_input = ''.join(re.split('\s+', get_input))    # 除去输入表达式中多余的空格
198         if get_input == '':     # 空字符,重新输入
199             continue
200         elif get_input == 'q':
201             print('\033[31;1m退出程序!\033[0m')
202             break
203         elif check_exp(get_input):    # 输入的表达式合法
204             exp = replace_symbol(get_input)     # 化简输入的表达式
205             print('化简后的表达式:\033[33;1m%s\033[0m\n' % exp)
206             parenthesis(exp)
207         else:
208             pass
计算器_python35
  1 #!/usr/bin/env python
  2 # -*- coding:utf-8 -*-
  3 # Version:Python2.7.10
  4 import re
  5 
  6 def check_exp(get_input):
  7     '''
  8     输入一个表达式,判断是否正确,返回一个去空格的表达式
  9     :param get_input: 获取的表达式
 10     :return: 返回一个去空格的表达式
 11     '''
 12     char_set = set(('0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
 13                     '+', '-', '*', '/', '%', '//', '**', '.', '(', ')'))       # 有效表达式的字符集合
 14     # 判断输入的字符合法,输入的表达式字符属于全集char_set为真
 15     if set(get_input).issubset(char_set):
 16         # 输入的表达式是乘号'*'、除号'/',百分号'%' 开头的,不合法
 17         if get_input.startswith('*') or get_input.startswith('/') or get_input.startswith('%'):
 18             print(u'\033[31;1m输入的表达式不正确,请重新输入!\033[0m')
 19             return False
 20         # 输入的表达式是乘号'*'、除号'/',百分号'%'、加号'+'、减号'-' 结尾的,不合法
 21         elif (get_input.endswith('*') or get_input.endswith('/') or get_input.endswith('%')
 22                 or get_input.endswith('+') or get_input.endswith('-')):
 23             print(u'\033[31;1m输入的表达式不正确,请重新输入!\033[0m')
 24             return False
 25         # 输入的表达式中,有两个点号或者加减号后面跟着乘除百分号的,不合法
 26         elif ('..' in get_input or '+*' in get_input or '+/' in get_input or '+%' in get_input
 27                 or '-*' in get_input or '-/' in get_input or '-%' in get_input):
 28             print(u'\033[31;1m输入的表达式不正确,请重新输入!\033[0m')
 29             return False
 30         else:
 31             return True
 32     else:
 33         print(u'\033[31;1m输入的表达式包涵其他字符,无法进行计算,请重新输入!\033[0m')
 34         return False
 35 
 36 def replace_symbol(exp):
 37     '''
 38     化简表达式,比如“++-”转换成“-",返回最简表达式
 39     :param exp: 需要化简的表达式
 40     :return:    化简后的表达式
 41     '''
 42     # 初始化一个替换字符的列表
 43     replace_char_list = [('+-', '-'), ('-+', '-'), ('++', '+'), ('--', '+'), ('*+', '*'),
 44                         ('/+', '/'), ('%+', '%'), ('//+', '//'), ('**+', '**')]
 45     flag = False    # 初始化标识符
 46     count = 0       # 初始化不匹配次数
 47     while not flag:
 48         for i in replace_char_list:
 49             if i[0] in exp:    # 要化简的字符在表达式中,则直接替换
 50                 exp = exp.replace(i[0], i[1])   # 把需要替换的键字符串修改为其值的字符串
 51                 break     # 中断for循环,进行下一次while循环
 52             else:
 53                 count += 1
 54             # 当count等于 len(replace_char_list)时,即 没有需要替换的字符了,退出循环
 55             if count == len(replace_char_list):
 56                 flag = True
 57 
 58         if exp.startswith('+'):
 59             exp = exp[1:]   # 除去表达式中开头的加号
 60     return exp
 61 
 62 def parenthesis(exp):
 63     '''
 64     运算括号里面的表达式,运算结果替代括号的内容,返回运算结果
 65     :param exp: 计算的表达式
 66     :return: None
 67     '''
 68     match = re.search('\(([\+\-\*\/%\/\/\*\*]*\d+\.*\d*){2,}\)', exp)  # 匹配括号内的表达式
 69     if match:   # 找到匹配的字符
 70         content = match.group()[1:-1]     # 获取匹配到的表达式,并过滤括号
 71         result = calculate(content)     # 调用计算函数,返回结束结果
 72         print(u'计算前的表达式:\033[32;1m%s\033[0m' % exp)
 73         print(u'括号中运算结果:\033[33;1m%s=%s\033[0m' % (content, result))
 74         replace_content = '(' + content + ')'
 75         exp = exp.replace(replace_content, result)      # 把运算结果替换表达式
 76         exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
 77         print(u'计算后的表达式:\033[34;1m%s\033[0m\n' % exp)
 78         parenthesis(exp)     # 递归执行括号处理
 79     else:
 80         result = calculate(exp)  # 当表达式没有括号时,直接计算表达式结果
 81         print(u'表达式运算结果:\033[35;1m%s\033[0m' % result)
 82 
 83 def power(exp):
 84     '''
 85     幂运算,返回运算结果
 86     :param exp: 幂运算的表达式
 87     :return: 计算后的表达式
 88     '''
 89     match = re.search('\d+\.?\d*[\*]{2}[\+\-]*\d+\.?\d*', exp)  # 匹配幂运算
 90     if match:   # 找到匹配的字符
 91         content = match.group()     # 获取匹配到的表达式
 92         if len(content.split('**')) > 1:
 93             n1, n2 = content.split('**')
 94             value = float(n1) ** float(n2)
 95             exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
 96             exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
 97             return power(exp)      # 递归重复匹配
 98         else:
 99             pass
100     else:
101         return exp  # 不匹配到,返回exp
102 
103 def mul_div(exp):
104     '''
105     做乘法、除法、取余、取整运算,返回运算结果
106     :param exp: 乘法、除法、取余、取整运算的表达式
107     :return: 计算后的表达式
108     '''
109     match = re.search('\d+\.?\d*[\*\/%\/\/]+[\+\-]?\d+\.?\d*', exp)  # 匹配乘、除、取余、取整运算
110     if match:   # 找到匹配的字符
111         content = match.group()     # 获取匹配到的表达式
112         if len(content.split('*')) > 1:
113             n1, n2 = content.split('*')
114             value = float(n1) * float(n2)   # 乘法运算
115             exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
116             exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
117             return mul_div(exp)
118 
119         elif len(content.split('//')) > 1:
120             n1, n2 = content.split('//')     # 取余运算
121             value = float(n1) // float(n2)
122             exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
123             exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
124             return mul_div(exp)
125 
126         elif len(content.split('%')) > 1:
127             n1, n2 = content.split('%')     # 除法运算
128             value = float(n1) % float(n2)
129             exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
130             exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
131             return mul_div(exp)
132 
133         elif len(content.split('/')) > 1:
134             n1, n2 = content.split('/')    # 取整运算
135             value = float(n1) / float(n2)
136             exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
137             exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
138             return mul_div(exp)
139 
140         else:
141             pass
142     else:
143         return exp  # 不匹配到,返回exp
144 
145 def add_sub(exp):
146     '''
147     加法、减法运算,返回运算结果
148     :param exp: 加法、减法运算的表达式
149     :return: 计算后的表达式
150     '''
151     match = re.search('\-?\d+\.?\d*[\+\-]+\d+\.?\d*', exp)  # 匹配加法、减法
152     if match:   # 找到匹配的字符
153         content = match.group()     # 获取匹配到的表达式
154         if len(content.split('+')) > 1:
155             n1, n2 = content.split('+')
156             value = float(n1) + float(n2)
157             exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
158             exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
159             return add_sub(exp)
160 
161         elif len(content.split('-')) > 1:
162             if len(content.split('-')) == 3:    # 被减数是负数的情况
163                 n1, n2 = content.split('-')[1:]     #  过滤分割列表开头的空白字符串
164                 value = float('-' + n1) - float(n2)   # 被减数需要添加一个负号
165                 exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
166                 exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
167                 return add_sub(exp)
168             elif len(content.split('-')) == 2:    # 被减数是正数的情况
169                 n1, n2 = content.split('-')     #  直接把两个操作数赋值给对应的变量
170                 value = float(n1) - float(n2)   # 做减法运算
171                 exp = exp.replace(content, str(value))   # 用计算的结果替换计算的表达式
172                 exp = replace_symbol(exp)   # 检查计算后的表达式是否存在类似 '+- '等字符,存在的话先替换,后执行
173                 return add_sub(exp)
174             else:
175                 pass
176         else:
177             pass
178     else:
179         return exp  # 不匹配到,返回exp
180 
181 def calculate(exp):
182     '''
183     获取一个运算表达式,返回运算结果
184     :param exp: 表达式
185     :return: 运算结果
186     '''
187     result = power(exp)         # 执行幂运算,返回运算结果
188     result = mul_div(result)    # 执行乘法、除法、取余、取整运算,返回运算结果
189     result = add_sub(result)    # 执行加法、减法运算,返回运算结果
190     return result
191 
192 if __name__ == '__main__':
193     print(u'\033[31;1m欢迎使用计算器\033[0m'.center(100,'='))
194     while True:
195         # 计算 s = '1-2 *(   (60- 30+(-40.0/5)*(9-2*5 / 3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'
196         get_input = raw_input(u'\n\033[32;1m请输入一个表达式 | 退出(q): \033[0m').strip()
197         get_input = ''.join(re.split('\s+', get_input))    # 除去输入表达式中多余的空格
198         if get_input == '':     # 空字符,重新输入
199             continue
200         elif get_input == 'q':
201             print(u'\033[31;1m退出程序!\033[0m')
202             break
203         elif check_exp(get_input):    # 输入的表达式合法
204             exp = replace_symbol(get_input)     # 化简输入的表达式
205             print(u'化简后的表达式:\033[33;1m%s\033[0m\n' % exp)
206             parenthesis(exp)
207         else:
208             pass
计算器_python27
posted @ 2016-02-18 10:41  suke99  阅读(995)  评论(0编辑  收藏  举报