发现eval的一个BUG

最近在弄Javascript,有一个需求是需要自定义公式。

而仅仅用公式是不行的,还要支持自定义函数。

那么问题来了,怎么匹配函数呢?

我的方式是用正则表达式。


例如有如下函数:

    { '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 




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值