Python之实现简单计算器功能
一,需求分析
要求计算一串包含数字+-*/()的类似于3*( 4+ 50 )-(( 100 + 40 )*5/2- 3*2* 2/4+9)*((( 3 + 4)-4)-4)表达式的数值
二,知识点
- 正则表达式
- 元素切片
- 函数
- 函数递归
三,流程分析
- 判断字符串是否包含()如果有先处理()内表达式并且计算结果返回新字符串
- 不包含()则直接计算表达式就先判断是否包含*/
- 先计算*/再计算+-返回结果
流程图如下
四,实现过程
1,正则表达式处理用户输入的字符串
cal1.py
1 2 3 4 5 6 7 | import re expression = '100.5+40*5/2-3*2*2/4+9' #\d代表数字\.代表数字意义上的小数点[\d\.]+表示可以匹配一个数字或者小数点.组成的字符串及可以代表所有数字 #匹配+及*需要加\转义 #匹配-/因为本身没有特殊函数不需要转义 l = re.findall( '[\d\.]+|\+|-|\*|/' ,expression) #l=['100.5', '+', '40', '*', '5', '/', '2', '-', '3', '*', '2', '*', '2', '/', '4', '+', '9'] |
2,首先定义出不包含()的字符串的计算方法
cal2.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | import re expression = '100.5+40*5/2-3*2*2/4+9' #\d代表数字\.代表数字意义上的小数点[\d\.]+表示可以匹配一个数字或者小数点.组成的字符串及可以代表所有数字 #匹配+及*需要加\转义 #匹配-/因为本身没有特殊函数不需要转义 l = re.findall( '[\d\.]+|\+|-|\*|/' ,expression) #l=['100.5', '+', '40', '*', '5', '/', '2', '-', '3', '*', '2', '*', '2', '/', '4', '+', '9'] #定义乘除法运算函数 def multdiv(l,x): #l是转换后的列表,x是传递的*或者/ #首先找到第一个*或者/的位置,需要计算的即为位置前后的两个数 #本列子a = 2 l[a-1] = 40 l[a+1] = 5 a = l.index(x) if x = = '*' : k = float (l[a - 1 ]) * float (l[a + 1 ]) else : k = float (l[a - 1 ]) / float (l[a + 1 ]) #依次删除找到的符号连同前后的两个元素 #本列子删除的是'40','*','5' del l[a - 1 ],l[a - 1 ],l[a - 1 ] #把计算结果转换成字符在插入列表原位置这样就完成了一次乘法或者除法运算 #并且把结果返回生成新的列表 l.insert((a - 1 ), str (k)) #调用多次该函数就会把*/计算出来后返回一个不包含*/的新列表 return l #定义计算函数,其中需要调用multdiv函数去除*/ def fun(l): #函数需要传递的参数为一个列表 #定义函数需要返回的结果 sum = 0 #假如列表不为空,无限循环处理列表 while l: #先判断列表是否包含*/执行对应的运算 #如果列表里面只有*没有/则把'*'作为实参传递给处理乘除法的函数multdiv if '*' in l and '/' not in l: multdiv(l, '*' ) #同理处理只包含/符号的 elif '/' in l and '*' not in l: multdiv(l, '/' ) #如果列表里面既包含*又包含/则先取到对应的索引值,比较大小后先处理前面再处理后面的 elif '*' in l and '/' in l: a = l.index( '*' ) b = l.index( '/' ) if a < b: multdiv(l, '*' ) else : multdiv(l, '/' ) #到这里已经处理完*/列表只剩下数字和+- else : #考虑到处理完*/以后的列表第一位可能是- #先把索引位置0 1 合并 #例如l = ['-','1'...] #合并后l = ['-1'] if l[ 0 ] = = '-' : l[ 0 ] = l[ 0 ] + l[ 1 ] del l[ 1 ] #处理完以后的列表只包含数字+ - #把列表第一位赋值给sum作为起始需要计算的基数 sum + = float (l[ 0 ]) #循环处理列表,因为列表的格式类似于['1','+','3','-','-4'] #所以需要取l[1] l[3] ...判断运算符号是+还是-然后根据情况进行累计加减 for i in range ( 1 , len (l), 2 ): if l[i] = = '+' : sum + = float (l[i + 1 ]) elif l[i] = = '-' : sum - = float (l[i + 1 ]) break return sum print ( 100.5 + 40 * 5 / 2 - 3 * 2 * 2 / 4 + 9 ) #206.5 a = fun(l) print (a) #206.5 |
这样处理的列表还有一个问题,假如需要处理的字符串有一串是这样的格式7*((1-4)-4) 使用fun计算一次为7*(-3-4) 再处理一次为7*(-7) 这样的字符串分割成列表为['7','*','-','7']需要在定义乘除以及加减方法的时候可以处理这种情况
cal3.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | import re expression = '100.5+40*5/2-3*2*2/4+9' #\d代表数字\.代表数字意义上的小数点[\d\.]+表示可以匹配一个数字或者小数点.组成的字符串及可以代表所有数字 #匹配+及*需要加\转义 #匹配-/因为本身没有特殊函数不需要转义 l = re.findall( '[\d\.]+|\+|-|\*|/' ,expression) #l=['100.5', '+', '40', '*', '5', '/', '2', '-', '3', '*', '2', '*', '2', '/', '4', '+', '9'] #定义乘除法运算函数 def multdiv(l,x): #l是转换后的列表,x是传递的*或者/ #首先找到第一个*或者/的位置,需要计算的即为位置前后的两个数 #本列子a = 2 l[a-1] = 40 l[a+1] = 5 a = l.index(x) if x = = '*' and l[a + 1 ] ! = '-' : k = float (l[a - 1 ]) * float (l[a + 1 ]) elif x = = '/' and l[a + 1 ] ! = '-' : k = float (l[a - 1 ]) / float (l[a + 1 ]) #如果*或者/后面对应的是-号则计算时候需要在前面加- elif x = = '*' and l[a + 1 ] = = '-' : k = - float (l[a - 1 ]) * float (l[a + 2 ]) elif x = = '/' and l[a + 1 ] = = '-' : k = - float (l[a - 1 ]) / float (l[a + 2 ]) #依次删除找到的符号连同前后的两个元素 #本列子删除的是'40','*','5' del l[a - 1 ],l[a - 1 ],l[a - 1 ] #把计算结果转换成字符在插入列表原位置这样就完成了一次乘法或者除法运算 #并且把结果返回生成新的列表 l.insert((a - 1 ), str (k)) #调用多次该函数就会把*/计算出来后返回一个不包含*/的新列表 return l #定义计算函数,其中需要调用multdiv函数去除*/ def fun(l): #函数需要传递的参数为一个列表 #定义函数需要返回的结果 sum = 0 #假如列表不为空,无限循环处理列表 while l: #先判断列表是否包含*/执行对应的运算 #如果列表里面只有*没有/则把'*'作为实参传递给处理乘除法的函数multdiv if '*' in l and '/' not in l: multdiv(l, '*' ) #同理处理只包含/符号的 elif '/' in l and '*' not in l: multdiv(l, '/' ) #如果列表里面既包含*又包含/则先取到对应的索引值,比较大小后先处理前面再处理后面的 elif '*' in l and '/' in l: a = l.index( '*' ) b = l.index( '/' ) if a < b: multdiv(l, '*' ) else : multdiv(l, '/' ) #到这里已经处理完*/列表只剩下数字和+- else : #考虑到处理完*/以后的列表第一位可能是- #先把索引位置0 1 合并 #例如l = ['-','1'...] #合并后l = ['-1'] if l[ 0 ] = = '-' : l[ 0 ] = l[ 0 ] + l[ 1 ] del l[ 1 ] #处理完以后的列表只包含数字+ - #把列表第一位赋值给sum作为起始需要计算的基数 sum + = float (l[ 0 ]) #循环处理列表,因为列表的格式类似于['1','+','3','-','-4'] #所以需要取l[1] l[3] ...判断运算符号是+还是-然后根据情况进行累计加减 for i in range ( 1 , len (l), 2 ): if l[i] = = '+' and l[i + 1 ] ! = '-' : sum + = float (l[i + 1 ]) elif l[i] = = '-' and l[i + 1 ] ! = '-' : sum - = float (l[i + 1 ]) #如果列表中+后面对应的是-则再推后一位计算- elif l[i] = = '+' and l[i + 1 ] = = '-' : sum - = float [l[i + 2 ]] #如果列表中-号后面对应的是-则再推后一位--得+ 计算+ elif l[i] = = '-' and l[i + 1 ] = = '-' : sum + = float [l[i + 2 ]] #循环完毕列表退出整个循环 break #把计算的结果sum作为返回值返回 return sum print ( 100.5 + 40 * 5 / 2 - 3 * 2 * 2 / 4 + 9 ) #206.5 a = fun(l) print (a) #206.5 |
以上程序可以处理不带任何括号的字符串,下面新加一个函数处理带有括号的字符串
cal4.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | import re expression = '100.5+40*5/2-3*2*2/4+9' #\d代表数字\.代表数字意义上的小数点[\d\.]+表示可以匹配一个数字或者小数点.组成的字符串及可以代表所有数字 #匹配+及*需要加\转义 #匹配-/因为本身没有特殊函数不需要转义 l = re.findall( '[\d\.]+|\+|-|\*|/' ,expression) #l=['100.5', '+', '40', '*', '5', '/', '2', '-', '3', '*', '2', '*', '2', '/', '4', '+', '9'] #定义乘除法运算函数 def multdiv(l,x): #l是转换后的列表,x是传递的*或者/ #首先找到第一个*或者/的位置,需要计算的即为位置前后的两个数 #本列子a = 2 l[a-1] = 40 l[a+1] = 5 a = l.index(x) if x = = '*' and l[a + 1 ] ! = '-' : k = float (l[a - 1 ]) * float (l[a + 1 ]) elif x = = '/' and l[a + 1 ] ! = '-' : k = float (l[a - 1 ]) / float (l[a + 1 ]) #如果*或者/后面对应的是-号则计算时候需要在前面加- elif x = = '*' and l[a + 1 ] = = '-' : k = - float (l[a - 1 ]) * float (l[a + 2 ]) elif x = = '/' and l[a + 1 ] = = '-' : k = - float (l[a - 1 ]) / float (l[a + 2 ]) #依次删除找到的符号连同前后的两个元素 #本列子删除的是'40','*','5' del l[a - 1 ],l[a - 1 ],l[a - 1 ] #把计算结果转换成字符在插入列表原位置这样就完成了一次乘法或者除法运算 #并且把结果返回生成新的列表 l.insert((a - 1 ), str (k)) #调用多次该函数就会把*/计算出来后返回一个不包含*/的新列表 return l #定义计算函数,其中需要调用multdiv函数去除*/ def fun(s): #函数需要传递的参数为一个字符串 #需要把字符串转换成列表 l = re.findall( '[\d\.]+|\+|-|\*|/' , s) #定义函数需要返回的结果 sum = 0 #假如列表不为空,无限循环处理列表 while l: #先判断列表是否包含*/执行对应的运算 #如果列表里面只有*没有/则把'*'作为实参传递给处理乘除法的函数multdiv if '*' in l and '/' not in l: multdiv(l, '*' ) #同理处理只包含/符号的 elif '/' in l and '*' not in l: multdiv(l, '/' ) #如果列表里面既包含*又包含/则先取到对应的索引值,比较大小后先处理前面再处理后面的 elif '*' in l and '/' in l: a = l.index( '*' ) b = l.index( '/' ) if a < b: multdiv(l, '*' ) else : multdiv(l, '/' ) #到这里已经处理完*/列表只剩下数字和+- else : #考虑到处理完*/以后的列表第一位可能是- #先把索引位置0 1 合并 #例如l = ['-','1'...] #合并后l = ['-1'] if l[ 0 ] = = '-' : l[ 0 ] = l[ 0 ] + l[ 1 ] del l[ 1 ] #处理完以后的列表只包含数字+ - #把列表第一位赋值给sum作为起始需要计算的基数 sum + = float (l[ 0 ]) #循环处理列表,因为列表的格式类似于['1','+','3','-','-4'] #所以需要取l[1] l[3] ...判断运算符号是+还是-然后根据情况进行累计加减 for i in range ( 1 , len (l), 2 ): if l[i] = = '+' and l[i + 1 ] ! = '-' : sum + = float (l[i + 1 ]) elif l[i] = = '-' and l[i + 1 ] ! = '-' : sum - = float (l[i + 1 ]) #如果列表中+后面对应的是-则再推后一位计算- elif l[i] = = '+' and l[i + 1 ] = = '-' : sum - = float (l[i + 2 ]) #如果列表中-号后面对应的是-则再推后一位--得+ 计算+ elif l[i] = = '-' and l[i + 1 ] = = '-' : sum + = float (l[i + 2 ]) #循环完毕列表退出整个循环 break #把计算的结果sum作为返回值返回 return sum #定义最终函数计算带有()的字符串 def calculate(expression): #函数传递的是一个字符串类似于(2-1)+(4-3)*3 #定义函数的最终返回值及计算结果 ans = 0 ex = [] #如果字符串不包含(则代表处理完()直接调用函数fun返回结果即可 if '(' not in expression: ans = fun(expression) return ans #否则处理() else : #使用search查找字符串中出现的第一个最里面的() #\([^()]+\)的意思是查找以(开始以)结尾的并且中间不包含任何()的字符串返回一个对象 #该对象有取出的字符串以及该字符串对应的索引 ret = re.search( '\([^()]+\)' ,expression) temp = ret.group() #temp = '(1+2)' ex = ret.span() #ex = (0,5) #切片去除首尾的()剩下不含()的字符串 sub = temp[ 1 : - 1 ] #sub = '1+2' #把不包含()的字符串作为参数传递给fun函数计算结果 k = fun(sub) #k = 3 #这样字符串被分为三段分别赋值给l1,l2,l3,重新拼接一下 l1 = expression[ 0 :ex[ 0 ]] #l1='' l2 = str (k) #l2='1' l3 = expression[ex[ 1 ]:] #l3='+(4-3)*3' expression = l1 + l2 + l3 #第一次处理完()拼接的结果为 #expression = '3+(4-3)*3' #递归调用函数第二次拼接后的结果是 #expression = '3+-1*3' #以此类推直到没有() return calculate(expression) a = calculate( '1+(2-3)*5' ) print (a) |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!