Preface
在Python中呢,有一个非常便利的一个函数,可以针对一个字符串(类似于1+3
)的运算而不需做任何的解析工作:
eval()
因无太多文章关于此点的介绍,故本篇文章即为介绍如何实现在Lua下的eval()
的功能(其实很简单)。
正文
问题来源
问题具体描述
其实,这个问题是出现在一个例子中,在这个例子中,我们需要对特定(或非特定)数字进行动态性的运算。
何为动态性地运算呢?
即,有以下数字:8、7、6、5、4,对这5个数字(顺序可以不变或可变,此处规定为不变)依次进行与运算符的运算。
譬如,我需要下面这个运算:
8 + 7 + 6 + 5 + 4
但是因为特殊的需求,又需要下面这个运算:
8 - 7 - 6 - 5 - 4
和下面这个运算:
8 x 7 + 6 / 5 - 4
其实运算的情况有很多,但是需要对其运算符进行动态地“注入”进去。
又譬如,运算符不止有“+ - * /”这四种,还可能包括了“^ % += -+ ……”等等情况,
如果需求异常特殊,可能还会出现类似于“i = i + k(k ≥ 1)”的等式,
因此使用“静态”的方法是不现实的。
问题总结
输入
8 7 6 5 4
输出
一个数值
要求
- 数字顺序不变
- 运算符可“动态注入”
解决方案
完美解决
此文只是使用loadstring
的方法,当然你可以使用在Lua中的Python库Lunatic Python。
你可以使用python.eval()
直接实现不费任何力气。
但是,本着钻研精神和深究到底的精神(其实是我不热爱Python),故使用
loadstring()
其实实现方式非常简单,但是中间有坑。
请看以下的示例:
通过以上的运算即可实现动态性地运算。
具体如何做思路:
- 将所需要的数字存入table中
- 将所需要的运算符存入table中
- 用for循环遍历相应的字符便可计算
坑
测试
这个地方其实也不算是坑,只能说你一不小心地时候会弄出不一样的东西来。下面介绍坑是什么、为什么以及怎么解决。
在得知正确地写法前,以下是测试代码
有无小数点不同的原因在于:"return a"
和"return " .. a
的位置(当然也包括b)。
为什么会这样呢?
我去stackoverflow上问了这个问题,两个人的说法有点含糊,让我来测试验证一下:
以下是测结果:
|
|
测试总结
第一组:当a在引号中的时候,不管后面的怎么变结果都存在小数点,即为
float
型数据。因为a在引号中又在loadstring
中,此过程为对string类型进行运算,
那么即会转换为float类型,后面的操作对象和“+”运算符(+也起到着影响因素,只是此处结果和运算结果相同)遇到了float类型,其结果会转换为float类型。(点我查看具体的转换关系)第二组:a在引号外的情况的时候,只有当后面的操作对象type类型是
number
时才不会有小数点存在,其余情况会有小数点存在。
这里需要注意的是,虽然..
是连接的作用,连接后的结果都是string
类型,但是连接前,b
是一个字符(串)(string类型
),而7
是一个数字(number
型)
虽然结果相同,但是运算出来的结果却是完全不同的第三组:没有a和b的情况,可以看出不管如何运算,其结果均没有小数点。
结论:
若a
或者b
没有引号包括,即作为string对象参与运算;
若有引号包括,即作为string类型参与运算,即return stringA + number
,其结果必然会被转换成float类型
由此结论可知“正确的”写法是:
|
|
总结
其实原理非常地简单,如果你弄不清你可能需要去看下Lua的基本知识或者重新看一遍分析过程。
有任何不懂的可以留言。
End