python之re模块

本次作业对re模块的要求还不算太高.

题目: 

实现能计算类似 
1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等类似公式的计算器程序
要求: 用户输入表达式,通过分析字符串来计算,不能使用eval

先普及一下寻找一个任意数字的正则表达式: [-+]?\d+(\.?\d+)?匹配任意带符号的数字.但在python中使用时,为了避免()带来的组优先问题,需要添加?:来破功[-+]?\d+(?:\.?\d+)?

分解:

1. 首先分析,表达式不支持"带未知数"的运算, 所以判断表达式格式: 

  表达式字符串全部由数字和+-*/()以及小数点组成,不满足条件则返回重新输入

2. 数学运算,此处不考虑如1**2或4//2这种计算方式

re.findall('[*/][*/]', exp)  # 如果返回值不为空则判断为错误输入,需重新输入

3. 需要先将表达式去空格: 直接exp.replace(' ', '')

4. 因作业要求中,表达式带括号,所以需要先找到最简括号算数表达式,计算出结果后替换到原表达式中,重新匹配最简算数表达式

re.findall('\([^()]+\)', exp)  # \((开头,为避免与表达式组混淆,需用\转义;[^()]+匹配至少一个字符,该字符中不存在()符号; \))结尾,同\(

  需要注意的是,替换回去的时候一定是无括号的.所以,如果计算结果是负数,会有这种情况: ...2-(-40/5)...结果...2--8...,因此需要对符号精简,也是用到数学方法

exp = exp.replace('++', '+').replace('+-', '-').replace('--', '+').replace('-+', '-')  # 精简符号,同时也可避免输入时手抖多输入符号...

5. 计算时,优先乘除运算.因乘除运算可单独将数字提取出来后,计算出的结果再添加符号,如-3*2可先计算3*2=6,再将符号还给他(当然这是下一步的加减运算,也可以不考虑)

  同上一条,也有可能如: ...2*(-40/5)...结果...2*-8...,所以表达式在寻找带有*和/的表达式时,需要将后面数字的符号考虑进去

min_exp_list = re.findall('\d+(?:\.?\d+)?[/*][-+]?\d+(?:\.?\d+)?', exp)  # 找带*/的表达式:数字[*/]数字 !!!*/号右边可能为负数(带符号)

6. 待括号表达式和乘除表达式计算完成并替换后,需要精简一下符号,也就需要再次调用replace('++', '+')

7. 开始计算剩下的所有加减运算.

  此时,可以光明正大的偷个懒,因为没有括号没有乘除符号,只剩下加减运算了,而所有的加减运算,都可以看成是两个带+-号的数字相加,故可直接带符号匹配每一个数字

re.findall('[-+]?\d+(?:\.?\d+)?', exp)  # 同样,为避免()带来的优先匹配,需要手动添加?:破功

  结果是一个带符号的数字的字符串组成的列表,将表中元素逐个转换为float类型,再sum(list)求和即可得出最后的结果

So Easy...

可是调了好久...

Block的地方:

1. 正则表达式的写法...(好吧,这个熟练就好了. 快速校验传送门: http://tool.chinaz.com/regex/

2. 匹配括号计算完毕,替换结果后括号还在...

3. 到底是用re.search逐个匹配+计算+替换还是用re.findall一次性匹配,再遍历list逐个计算+替换呢?

4. 匹配乘除运算时,最容易忽视被乘/除数是否带符号,一旦是带符号的,结果就返回None了.这里卡了好久

...

本次作业,正则表达式貌似只与数字打交道了.字母什么的\w啊\W啊什么的,有机会再看吧

...

To Be Continued...

猜你喜欢

转载自www.cnblogs.com/aliter/p/9027318.html