用Python最原始的函数模拟eval函数的浮点数运算功能
前几天看一个网友提问,如何计算'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
用Python最原始的函数模拟eval函数的浮点数运算功能的更多相关文章
- 用Python最原始的函数模拟eval函数的浮点数运算功能(2)
这应该是我编程以来完成的难度最大的一个函数了.因为可能存在的情况非常多,需要设计合理的参数来控制解析流程.经验概要: 1.大胆假设一些子功能能够实现,看能否建立整个框架.如果在假设的基础上都无法建立, ...
- python中的exec()函数和eval()函数
exec()函数 exec函数用于执行存储在字符串中的python语句 >>> exec("x=1") >>> x 但有时候,直接这样执行可能会 ...
- 编写函数模拟strcpy()函数功能
strcpy(字符数组1,字符串2) strcpy( )用于将字符串2复制到字符数组1中 /* strcpy(字符数组1,字符串2) strcpy( )用于将字符串2复制到字符数组1中 模拟strcp ...
- R语言parse函数与eval函数的字符串转命令行及执行操作
parse()函数能将字符串转换为表达式expression:eval()函数能对表达式求解 A <- : B <- 'print(A)' class(B) C <- parse(t ...
- Python使用map,reduce高阶函数模拟实现Spark的reduceByKey算子功能
# 使用默认的高阶函数map和reduce import randomdef map_function(arg): # 生成测试数据 return (arg,1) list_map = list(m ...
- python 内置函数input/eval(22)
python的内置函数其实挺多的,其中input和eval算得上比较特殊,input属于交互式内置函数,eval函数能直接执行字符串表达式并返回表达式的值. 一.input函数 input是Pytho ...
- [Effective JavaScript 笔记]第17条:间接调用eval函数优于直接调用
eval函数不仅仅是一个函数.大多数函数只访问定义它们所在的作用域,而不能访问除此之外的作用域(词法作用域).eval函数具有访问调用它时的整个作用域的能力.编译器编写者首次设法优化js时,eval函 ...
- Matlab匿名函数,子函数,私有函数,重载函数,eval和feval函数
匿名函数,子函数,私有函数等函数类型 匿名函数: 匿名函数没有函数名,也不是.m文件,只包含一个表达式和输入输出参数. Fxy=@(x,y)x.^y+3*x*y x,y为输入输入参数,Fxy为函数名 ...
- python笔记-调用eval函数出现invalid syntax错误
本来是想打算使用eval函数对变量进行赋值的,没想到出现了invalid syntax错误.源代码如下 In [2]: eval('a = 1') File "<string>& ...
随机推荐
- 关于Goldwell平台推出赠金及手数奖励
关于Goldwell平台推出赠金及手数奖励 Goldwell平台是一家拥有30多年现货黄金经验平台,平台位于柬埔寨金边,是一家国际衍生品的经纪公司.Goldwell平台它对柬埔寨金融市场和客户绝对的承 ...
- 设置python爬虫IP代理(urllib/requests模块)
urllib模块设置代理 如果我们频繁用一个IP去爬取同一个网站的内容,很可能会被网站封杀IP.其中一种比较常见的方式就是设置代理IP from urllib import request proxy ...
- [LeetCode] Range Addition II 范围相加之二
Given an m * n matrix M initialized with all 0's and several update operations. Operations are repre ...
- [SDOI 2008]仪仗队
Description 作为体育委员,C君负责这次运动会仪仗队的训练.仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是 ...
- [TJOI 2010]中位数
Description 给定一个由N个元素组成的整数序列,现在有两种操作: 1 add a 在该序列的最后添加一个整数a,组成长度为N + 1的整数序列 2 mid 输出当前序列的中位数 中位数是指将 ...
- 【LSGDOJ1383】修改回文 dp
题目描述 为了跟踪所有的牛,农夫JOHN在农场上装了一套自动系统. 他给了每一个头牛一个电子牌号 当牛走过这个系统时,牛的名字将被自动读入. 每一头牛的电子名字是一个长度为M (1 <= M & ...
- 51Nod 1331 狭窄的通道
有一个长为L的狭窄通道,我们假设这个通道在x轴上,其两个出口分别在x=0与x=L处.在这个通道里有N只狼,第i只狼有一个初始位置ai,它想到达位置bi(0<=i=L处空间足够大可以装下任意数量的 ...
- 提高Mysql查询速度的一些建议(转).
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...
- python中的缩进问题
python中没有{}来表示代码块,而是用缩进来表示,刚开始写python代码,没有注意缩进,结果各种报错(( ╯□╰ )). 在python中的原则就是同一层次的代码一定要有相同的缩进!!! 从上图 ...
- Mysql锁机制--乐观锁 & 悲观锁
Mysql 系列文章主页 =============== 从 这篇 文章中,我们知道 Mysql 并发事务会引起更新丢失问题,解决办法是锁.所以本文将对锁(乐观锁.悲观锁)进行分析. 第一部分 悲观锁 ...