概述
前几天看一个网友提问,如何计算'1+1'这种字符串的值,不能用eval函数.
我仿佛记得以前新手时,对这个问题完全不知道如何下手.
我觉得处理括号实在是太复杂了,多层嵌套括号怎么解析呢?一些多余的括号呢?
而在没有括号的情况下,处理不同运算符之间的优先级又很头疼.
而'**'这种占2个字符的运算符,还有着奇特的优先级规则,x**y**z应先计算y**z,并且如果z后面还跟着**的话,则不能先计算y**z..这是最难的地方!
但是,今天我竟然把它实现了!而且是用最原始的函数实现的,它们是:
str,s.isdigit,s.find,s.count,
dict,float
if,in,and,not
==,>=,+(字符串连接)
float对象的6个方法不计算在内,这是无法避免的基础函数.
而str,float,dict只是起到类型转换或初始化数据的作用.所以真正用到的函数更是少之又少.
可能正是因为如此,我在程序设计上花了很多的心思.我用了非常多的if判断.显得有些难以看懂.而实际上每个分支都对应一种简单的情况.
唯一难的地方在于幂的递归运算(get_rig_rest函数).
这令我非常激动.这让我意识到自己解决复杂问题的能力!
另外应该指出,我的思路来自于前段时间学习Scheme时重写一些基本函数所养成的递归思考的习惯.
同时,Python真的是太方便和强大了,快速的print让测试+修改十分简单,极大提高了大脑解决抽象问题的能力(没有print,也许你要浪费很多笔,纸和时间).
dic={'+':float.__add__, '-':float.__sub__, '*':float.__mul__, '/':float.__floordiv__, '%':float.__mod__, '**':float.__pow__,} priority=dict((('**',3),('*',2),('/',2),('%',2),('+',1),('-',1))) def prt(opf,p_opf): '幂运算符总是最优先,即使左边也是幂运算符' if p_opf=='**': return False return priority[opf]>=priority[p_opf] def get_val(lef,opf,rig): return str(dic[opf](float(lef),float(rig))) def isfloat(s): return s.isdigit() or s=='.' def get_brace(s,start=0): pos=s.find(')',start)+1 brace=s[:pos] if brace.count('(')==brace.count(')'): return brace,s[pos:] return get_brace(s,pos) def get_rig_rest(s,num=''): '分裂为数字+剩余部分' '如果数字后是幂运算符,则需要计算该数字的幂,将结果作为数字部分返回' if s[:2] =='**': pow_num,rest=get_rig_rest(s[2:]) return get_val(num,'**',pow_num),rest if s=='' or s[0] in dic: return num,s if s[0]=='(': brace,rest=get_brace(s) return ieval(brace[1:-1]),rest if isfloat(s[0]): return get_rig_rest(s[1:],num+s[0]) def ieval(s,lef='',opf=None,rig=''): if not opf and not s: return lef if not opf and isfloat(s[0]): return ieval(s[1:],lef+s[0],opf,rig) if not opf and s[0] in dic: if s[1]=='*': return ieval(s[2:],lef,'**',rig) return ieval(s[1:],lef,s[0],rig) if not opf and s[0]=='(': brace,rest=get_brace(s) if not rest: return ieval(brace[1:-1]) return ieval(rest,lef+ieval(brace[1:-1]), opf,rig) if opf and not s: return get_val(lef,opf,rig) if opf and s[0]=='(': brace,rest=get_brace(s) if not rest: return get_val(lef,opf,ieval(brace[1:-1])) return ieval(lef+opf+ieval(brace[1:-1])+rest, '',None,'') if opf and isfloat(s[0]): return ieval(s[1:],lef,opf,rig+s[0]) if opf and s[0] in dic: number=2 if s[1]=='*' else 1 p_opf=s[:number] if prt(opf,p_opf): return ieval(s,get_val(lef,opf,rig),None,'') p_rig,p_rest=get_rig_rest(s[number:]) return ieval(lef+opf+get_val(rig,p_opf,p_rig)+p_rest, '',None,'') test=['1+2+3', #常规 '1+2*9', #简单运算符优先级 '1+2*(3+4)', #简单运算符优先级+括号 '4**3**2', #幂运算优先级 '3+2*0.5**(2+2**2)',#多重优先级+括号 '(1+2)*(2+3)', #并列括号 '((9+3)/2)', #嵌套括号 '((1234)-1)', #多余括号 '((1+3**2)*((2%3+(3+3*2**3))*(4-1)*(1+2)+5*6)*4)'] #复杂情形 for x in test: print(ieval(x),'---',eval(x))
结果:
>>> 6.0 --- 6 19.0 --- 19 15.0 --- 15 262144.0 --- 262144 3.03125 --- 3.03125 15.0 --- 15 6.0 --- 6.0 1233.0 --- 1233 11640.0 --- 11640
转载于:https://www.cnblogs.com/xiangnan/p/3413522.html
最后
以上就是坦率大炮为你收集整理的用Python最原始的函数模拟eval函数的浮点数运算功能的全部内容,希望文章能够帮你解决用Python最原始的函数模拟eval函数的浮点数运算功能所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复