头疼,其实这个程序在我看的视频当中是当做re模块的运用来进行测试的,而到了我这里就成了简化版的了,因为我实在是做吐了,恕小弟无能,只能做简化版的。为何说是简化版呢,因为要求是给的计算式是多层嵌套的小括号“()”,然后计算的时候不能用eval方法,eval是个好东西啊,他能直接得到字符串中的结果,比如eval(“23+34*45/345-34”)=结果,是可以直接给你返回算术式的结果的,如果你自己处理这段字符串的话就要花好多工夫拆解字符串。我的简化版是将多层小括号给分为了小括号“()”、中括号“【】”、大括号“{}”,不允许使用多层相同括号连续嵌套(相应的不允许超过三层,超过三层,小弟无能为力),而我觉得,想要区分不同的层级的小括号“(()())”是需要下功夫用re正则去匹配的,而我这个用是用到正则了,但用的很少,重点全在如何自己写代码实现eval的功能了。

效果图:

另附一张各步骤计算详解

源代码:

import re

def Get_FuH(As):
As = As.replace('--','+')
As = As.replace('+-', '+')
As = As.replace('/-', '/')
As = As.replace('*-', '*')
End = []
As = list(As)
if (As[1] == '-'):
As.pop(1)
for i in As:
if(i == '/' or i == '+' or i == '*' ):
End.append(i)
elif(i == '-'):
End.append('+')
for i in End:
if(i == ''):
End.pop(End.index('')) return End
def Get_Num(As):
As = As.replace('--', '-')
As = As.replace('+-', '-')
As = As.replace('/-', '-')
As = As.replace('*-', '-')
As = list(As)
Get = []
End = []
for i in As:
if(i <= "9" and i >= "0" or i == '.'):
Get.append(i)
else:
End.append(''.join(Get))
Get = []
if(i == '-'):Get.append(i)
for i in End:
if(i == ''):
End.pop(End.index(''))
for i in End:
if(i == ''):
End.pop(End.index(i))
return End def Do_Xiao(As):
a = re.findall("\([+\-*/0-9.]*\)",As)
# print(a)
for i in a:
TiH = i
ShuZ = Get_Num(TiH)
FuH = Get_FuH(TiH)
ShuZ_New = []
FuH_New = []
# print(TiH)
# print(ShuZ)
# print(FuH)
for q in FuH:
if (q == '*'):
m = FuH.index('*')
End = float(ShuZ[m]) * float(ShuZ[m + 1])
ShuZ[m] = 0
FuH[m] = 0
ShuZ[m+1] = End
elif (q == '/'):
m = FuH.index('/')
End = float(ShuZ[m]) / float(ShuZ[m + 1])
ShuZ[m] = 0
FuH[m] = 0
ShuZ[m + 1] = End
for i in ShuZ:
if (i != 0): ShuZ_New.append(i)
for i in FuH:
if (i != 0): FuH_New.append(i)
# print(ShuZ_New)
# print(FuH_New)
for i in FuH_New:
if (i == '+'):
n = FuH_New.index('+')
End = float(ShuZ_New[n]) + float(ShuZ_New[n + 1])
ShuZ_New[n] = 0
FuH_New[n] = 0
ShuZ_New[n + 1] = float(End)
elif (i == '-'):
n = FuH_New.index('-')
End = float(ShuZ_New[n]) - float(ShuZ_New[n + 1])
ShuZ_New[n] = 0
FuH_New[n] = 0
ShuZ_New[n + 1] = float(End)
for p in ShuZ_New:
if (p != 0):
As = As.replace(TiH, str(p))
return As
def Do_Zhong(As):
As = As.replace("[","(")
As = As.replace("]",")")
As = Do_Xiao(As)
return As def Do_Da(As):
As = As.replace("{","(")
As = As.replace("}",")")
# print(As)
As = Do_Xiao(As)
return As def End_end(As):
As = '(' + As + ')'
End = Do_Xiao(As)
return End if __name__ == '__main__':
AA = "1-2*{[60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14)]-(-4*3)/(16-3*2)}"
BB = "34+45*{44+34*45+44/45}-{[34*45/44]*(456+466*345-3445/455)}"
As = input("请输入你要计算的式子:")
As = Do_Xiao(As)
print(As)
As = Do_Zhong(As)
print(As)
As = Do_Da(As)
print(As)
End = End_end(As)
print(End) 解析:我的整体思路很简单,就是按顺序一步步提取,先用正则把小括号的内容提取出来,因为有格式要求,所以提取的小括号的内容都是闭合的(即()中间不会出现()或者单边括号,匹配较为容易)。对提取的内容进行处理:定义了几个函数:1、提取数字,我将提取的字符串转为列表,然后把通过运算符分割的数字(之所以取运算符是因为有多位数还有小数点的存在,这样可以将一个数字完整的存放在一起)按个存放到一个列表中。2、提取运算符,直接扫描字符串列表提取即可。3、运算,因为运算符是两个数进行运算,所以通过循环运算符,每一个运算符都是运算符左右两个数的和。为了区分优先级(先乘除后加减),我进行了两边循环符号,且第二遍循环是在第一次的基础上删除了乘除运算符后的列表。即第一遍循环只算乘除,第二遍再算加减。4、中括号转小括号,一定要在小括号运算完,公式中没有小括号才能调用。5、大括号转小括号,同理中括号,因为如果大括号转成小括号,里面还有中括号会卡在中括号上没有匹配符。
再说说中间的遇到的一些bug,也是导致代码混乱的地方,这些我都没来的及优化,测视了两个算术式没问题就不搞了,头疼。1、提取数字,“-”是个大问题,到底把他算在运算符列表中呢还是算在数字列表中呢,我选择的是放在数字中,即数字分正负,由此我需要判断“+-”、“--”、“/-”、“*-”,后两个还好说,前两个真是搞死了,就在那算负负、正正的逻辑去了,还要在表达式中进行替换工作,将双符号进行缩减成标准的单符号传进符号列表中,因为符号列表的数目一旦不对,就会导致数字列表没有匹配正确(这也是最麻烦的地方,中间出了好几次超出列表范围的bug)。另一个问题比较严重的问题是在乘除算完给加减新的列表的时候,因为有连乘连除的存在,所以我需要将计算的结果再存到列比中循环利用,我的方法是算一个弹出一个,既可以继续运行,还可以缩减列表,到最后符号列表为空,数字列表还剩一个结果。呵呵,理想很丰满,结果最大的bug出来了,找了好半天,把所有的循环都输出了一遍才找到原因:因为我是用for循环,通过i in 符号列表,然后当i匹配到运算符,就找到这个下表,然后弹出去这个运算符元素,数字列表弹出去两个数字,但当我符号弹出去这个后,列表索引自动迁移,导致i+1成了i,i+1还没进行循环,就变成了下一次循环到了i+2,简单说就是每一次循环i+1,当我弹出当前位置i后,i(y) = i+1,且这是在本次循环结束前,所以当下一次循环开始时,其实是y+1,也就是上一次循环中的i(i已经被弹出去了,i成了i+1)的后面的后面这个元素,及跳过了一个i的循环,为了避免这种情况,我不弹出元素,而是全都初始化为0,当乘除运算完后,再进行“除0”,即构造新列表再次进行加减运算。
使用说明:大、中、小括号必须数目,位置等对称,且不能乱套,中规中举的小中大或者小中、小大、中大,不可小套大。式子中用到那种括号就调用一次对应的函数,且从小往大一层层的调。我没有设检查式子是否合规,讲道理应该不会再出什么问题了,AA的式子是我照着这个写的程序,BB是用来测试的,我只测试了这一个,毕竟长公式写起来也麻烦,自己再在手机上算一遍也麻烦,但AA、BB的式子我都在手机上算过了,都对,且更精确。

Python学习之函数(多层函数)、re模块的正则匹配--计算复杂加减乘除的更多相关文章

  1. Python学习笔记之常用函数及说明

    Python学习笔记之常用函数及说明 俗话说"好记性不如烂笔头",老祖宗们几千年总结出来的东西还是有些道理的,所以,常用的东西也要记下来,不记不知道,一记吓一跳,乖乖,函数咋这么多 ...

  2. 常用的re模块的正则匹配的表达式

    07.01自我总结 常用的re模块的正则匹配的表达式 一.校验数字的表达式 1.数字 ^[0-9]\*$ 2.n位的数字 ^\d{n}$ 3.至少n位的数字 ^\d{n,}$ 4.m-n位的数字 ^\ ...

  3. Python学习笔记4(函数与模块)

    1.Python程序的结构 Python的程序由包(package).模块(module)和函数组成. 模块是处理一类问题的集合,由函数和类组成. 包是由一系列模块组成的集合.包是一个完成特定任务的工 ...

  4. python 学习笔记6(函数)

    函数 定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 特性: 1.减少代码重复 2.保持代码的一致性 3.方便修改,可扩展性 函数的创建 #简单 ...

  5. python学习交流 - 内置函数使用方法和应用举例

    内置函数 python提供了68个内置函数,在使用过程中用户不再需要定义函数来实现内置函数支持的功能.更重要的是内置函数的算法是经过python作者优化的,并且部分是使用c语言实现,通常来说使用内置函 ...

  6. Python学习笔记 - 高阶函数

    高阶函数英文叫Higher-order function.什么是高阶函数?我们以实际代码为例子,一步一步深入概念. 变量可以指向函数 以Python内置的求绝对值的函数abs()为例,调用该函数用以下 ...

  7. Python学习(六) —— 函数

    一.函数的定义和调用 为什么要用函数:例如,计算一个数据的长度,可以用一段代码实现,每次需要计算数据的长度都可以用这段代码,如果是一段代码,可读性差,重复代码多: 但是如果把这段代码封装成一个函数,用 ...

  8. Python学习笔记010——匿名函数lambda

    1 语法 my_lambda = lambda arg1, arg2 : arg1 + arg2 + 1 arg1.arg2:参数 arg1 + arg2 + 1 :表达式 2 描述 匿名函数不需要r ...

  9. [python学习] 语言基础—排序函数(sort()、sorted()、argsort()函数)

    python的内建排序函数有 sort.sorted两个. 1.基础的序列升序排序直接调用sorted()方法即可 ls = list([5, 2, 3, 1, 4]) new_ls = sorted ...

随机推荐

  1. idea激活破解

    下载链接:https://pan.baidu.com/s/1BADk1MCm0YxtB6zoX0DivA 提取码 ze9m将破解补丁放到bin文件中jetbrains-all.jar 在这俩个文件最后 ...

  2. /bin /usr/bin /sbin /usr/sbin 目录的作用

    /bin是系统的一些指令.bin为binary的简写主要放置一些系统的必备执行档例如:cat.cp.chmod df.dmesg.gzip.kill.ls.mkdir.more.mount.rm.su ...

  3. Lua 协程和线程区别

    协程就是协程,不是线程. CPU执行单位是线程,不是什么协程. 协程,是同步执行,不是并行,只是切了一个上下文了,为你保存原来的上下文而已. 切到第二个协程时,原来的协程处于挂起状态. 这个特指lua ...

  4. JavaScript特效源码(8、其他特效)

    1.中文日期 中文日期[无须修改][共1步]] ====1.将以下代码加入HEML的<body></body>之间 <script LANGUAGE="Java ...

  5. Python全栈开发:html标签

    Html是什么? htyper text markup language 即超文本标记语言 超文本: 就是指页面内可以包含图片.链接,甚至音乐.程序等非文字元素. 标记语言: 标记(标签)构成的语言. ...

  6. IDEA将代码推送至远程GitHub仓库

    1 在项目根路径下添加.gitignore文件 2 创建本地git仓库 3 git add操作 快捷键 ctrl+alt+a 4 git commit操作 快捷键ctrl+k 5 git push操作 ...

  7. re模块补充

    )# 后面加数字代表前面多少个进行替换print(ret8) # stars466c7#7.subn() 会返回替换了多少次ret9=re.subn('\d','asd','sh8sd6sds7smm ...

  8. IO流读取和写入文件

    package com.xmlmysql.demo.config; import java.io.BufferedReader; import java.io.BufferedWriter; impo ...

  9. zabbix自动发现主机(转)

    zabbix自动发现主机 2018年06月15日 18:02:52 loyal-Wang 阅读数:817更多 个人分类: zabbix   版权声明:本文为博主原创文章,转载请注明出处. https: ...

  10. .Net StackFrame

    StackFrame指的是一个.net运行的时候堆栈上的一个帧(Frame),每次进入一个方法的时候就会有一个新的方法帧压入线程执行堆栈,可以通过StackFrame获取相关的信息,比如当前代码所在文 ...