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
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