发现eval的一个BUG
2015-12-25 13:53
537 查看
最近在弄Javascript,有一个需求是需要自定义公式。
而仅仅用公式是不行的,还要支持自定义函数。
那么问题来了,怎么匹配函数呢?
我的方式是用正则表达式。
例如有如下函数:
这个函数在很多语言里面都有,我就不做过多解释了。
P.S.:这里为了简便起见,前两个参数我仅仅用 .*? 来代替了,实际上不是这样的,需要判断参数的格式是否符合规范。
Js中使用
就可以匹配了,看是否命中。
因为这个函数的定义是从数据库中读取的,得出来的Regexp是一个字符串,所有还要用eval转换一下才能成为正则表达式匹配字符串。
变成这样:
在实际测试的过程中,产生了如下结果:
第三个参数只要匹配命中第一个字符串,就认为是命中的,后面无论接上什么,都会命中……
如果直接使用正则字符串,就不会出现这个问题。
这个暂时没有找到解决的办法,只能前台判断一次之后后台再判断一次。
Python中无此问题,因为正则字符串无需eval转换。
------------------------------------------------------
2016-05-09更新
话说,这其实不是bug啦,只是我正则写得不对。
要匹配形如 DateDiff(1,2,d) 的字符串,正则应该这么写:
DateDiff\(.*?,.*?,([ymdhs]|(mi))\)
之前少了两个小括号,匹配的时候就有点问题了。
匹配的时候改用exec就更容易发现问题。
而且,把字符串转化成正则字符串也不建议用eval,而应该 new 一个RegExp会比较好。
例如:
var Parren = new RegExp('DateDiff\\(.*?,.*?,([ymdhs]|(mi))\\)', 'i');
不知道你留意到没有,括号是需要“额外”转义的。
因为如果不加 \\ ,那么结果 parren 就会是 “/DateDiff(.*?,.*?,([ymdhs]|(mi)))/i”
少了斜杠,则此表达式永远无法匹配命中。
更新过后,上述正则表达式的测验脚本如下:
测验结果:
而仅仅用公式是不行的,还要支持自定义函数。
那么问题来了,怎么匹配函数呢?
我的方式是用正则表达式。
例如有如下函数:
{ 'Name':'DateDiff', 'Desc':'计算从 StartDate 到 EndDate 之间的时间单位(Unit)个数, Unit 可以为:"y/m/d/h/mi/s",依次代表 "年/月/日/时/分/秒"', 'Returns':'Int 时间单位个数(不包含 EndDate )', 'Format':'DataDiff(StartDate,EndDate,Unit)', 'Regexp':'/DateDiff\((.*?),(.*?),([ymdhs]|mi)\)/i', 'KeyPos':'0,1', }
这个函数在很多语言里面都有,我就不做过多解释了。
P.S.:这里为了简便起见,前两个参数我仅仅用 .*? 来代替了,实际上不是这样的,需要判断参数的格式是否符合规范。
Js中使用
(Regexp).test(SomeString)
就可以匹配了,看是否命中。
因为这个函数的定义是从数据库中读取的,得出来的Regexp是一个字符串,所有还要用eval转换一下才能成为正则表达式匹配字符串。
变成这样:
(eval(Regexp)).test(SomeString)就是这个小转换,问题来了。
在实际测试的过程中,产生了如下结果:
var RegexpStr = '/DateDiff\((.*?),(.*?),([ymdhs]|mi)\)/i'; console.log( (eval(RegexpStr)).test('DateDiff(1,2,3)') ); console.log( (eval(RegexpStr)).test('DateDiff(1,2,d)') ); console.log( (eval(RegexpStr)).test('DateDiff(1,2,d3)') ); console.log( (eval(RegexpStr)).test('DateDiff(1,2,daa43523452345)') );输出:
false true true true哭笑不得。
第三个参数只要匹配命中第一个字符串,就认为是命中的,后面无论接上什么,都会命中……
如果直接使用正则字符串,就不会出现这个问题。
这个暂时没有找到解决的办法,只能前台判断一次之后后台再判断一次。
Python中无此问题,因为正则字符串无需eval转换。
------------------------------------------------------
2016-05-09更新
话说,这其实不是bug啦,只是我正则写得不对。
要匹配形如 DateDiff(1,2,d) 的字符串,正则应该这么写:
DateDiff\(.*?,.*?,([ymdhs]|(mi))\)
之前少了两个小括号,匹配的时候就有点问题了。
匹配的时候改用exec就更容易发现问题。
而且,把字符串转化成正则字符串也不建议用eval,而应该 new 一个RegExp会比较好。
例如:
var Parren = new RegExp('DateDiff\\(.*?,.*?,([ymdhs]|(mi))\\)', 'i');
不知道你留意到没有,括号是需要“额外”转义的。
因为如果不加 \\ ,那么结果 parren 就会是 “/DateDiff(.*?,.*?,([ymdhs]|(mi)))/i”
少了斜杠,则此表达式永远无法匹配命中。
更新过后,上述正则表达式的测验脚本如下:
var RegexpStr = 'DateDiff\\(.*?,.*?,([ymdhs]|(mi))\\)'; var Parren = new RegExp(RegexpStr, 'i'); console.log(eval('/'+RegexpStr+'/i'),Parren) console.log( (/DateDiff\(.*?,.*?,([ymdhs]|(mi))\)/i).exec('DateDiff(1,2,3)') ); console.log( (/DateDiff\(.*?,.*?,([ymdhs]|(mi))\)/i).exec('DateDiff(1,2,d)') ); console.log( (/DateDiff\(.*?,.*?,([ymdhs]|(mi))\)/i).exec('DateDiff(1,2,d3)') ); console.log( (/DateDiff\(.*?,.*?,([ymdhs]|(mi))\)/i).exec('DateDiff(1,2,daa43523452345)') ); console.log( (eval('/'+RegexpStr+'/i')).exec('DateDiff(1,2,3)') ); console.log( (eval('/'+RegexpStr+'/i')).exec('DateDiff(1,2,d)') ); console.log( (eval('/'+RegexpStr+'/i')).exec('DateDiff(1,2,d3)') ); console.log( (eval('/'+RegexpStr+'/i')).exec('DateDiff(1,2,daa43523452345)') ); console.log( Parren.exec('DateDiff(1,2,3)') ); console.log( Parren.exec('DateDiff(1,2,d)') ); console.log( Parren.exec('DateDiff(1,2,d3)') ); console.log( Parren.exec('DateDiff(1,2,daa43523452345)') );
测验结果:
/DateDiff\(.*?,.*?,([ymdhs]|(mi))\)/i /DateDiff\(.*?,.*?,([ymdhs]|(mi))\)/i /*这一行的括号及斜杠都被csdn吞了,各位测验的时候注意一下。*/ null ["DateDiff(1,2,d)", "d", undefined, index: 0, input: "DateDiff(1,2,d)"] null null null ["DateDiff(1,2,d)", "d", undefined, index: 0, input: "DateDiff(1,2,d)"] null null null ["DateDiff(1,2,d)", "d", undefined, index: 0, input: "DateDiff(1,2,d)"] null null
相关文章推荐
- 深入浅出java并发
- LeetCode() Binary Tree Level Order Traversal
- 软件工程学习总结
- SQLMAP 实例COOKBOOK
- IOS给UILabel文本框增加下划线和中划线
- RxJava与RxAndroid 接收消息通知
- extjs 时间控件默认时间
- 关于 margin padding的一点感想
- get请求返回的是字符串,将其改成字典
- SAP ALL compile code: SGEN
- SAP ALL compile code: SGEN
- SAP ALL compile code: SGEN
- Linux运维 第四阶段(八)MySQL REPLICATION(SSL)
- Python continue pass和break
- Javascript学习笔记2.3 Javascript与DOM实现动态表格效果
- Linux常用Terminal命令與快捷鍵參考
- 多指标综合评价中指标正向化和无量纲化方法的选择
- android studio 的奇葩环境问题
- 策略模式(Strategy)
- 听说你会打地鼠(动态规划dp)