js正则表达式中关于零宽断言的奇异现象
2016-02-29 17:00
573 查看
碰到一个特别的需求,就是有一段Sql Server 的 SQL片段,内容大概就是所有JOIN表的集合,要求把这个SQL片段分割成数组,每个元素就是包含单个表的字符串。
例如:
SQL = INNER JOIN Sale b ON 1=1 LEFT JOIN OutStock c ON 1=1 RIGHT JOIN BunissMan c ON 1=1
分割成:
["INNER JOIN Sale b ON 1=1 ","LEFT JOIN OutStock c ON 1=1 ","RIGHT JOIN BunissMan c ON 1=1 "]
还好理解吧?
实现的方式其实挺多,循环遍历分割、正则分割等等。
为了感觉高大上一点,决定了正则。
就是在实验的过程中,发现了一个奇异的现象。
本来想测试一下各种JOIN的匹配情况,于是采用正则表达式如下:
/(?=INNER)|(?=LEFT)|(?=RIGHT)|(?=FULL OUTER) JOIN/
采用match,没有匹配到我想要的东西,但是,split却出来了结果:
测试源码:
测试结果:
着实让我又惊又喜。
喜的是,这个需求这么容易结束了。
惊的是,不知道这是怎么得到的结果。
在python里面测试了相同的零宽断言,发现是不能进行分割的。
本着研究的精神继续探索。
分析一下:
第一行将234作为分隔符分割了,很好理解。
第二行使用了零宽断言,能匹配2后面紧接着是3的的“分隔符”,所以将前面的“2”作为分隔符,而后面的2接着9,不能分隔。
第三行一开始困惑了我,理论上应该能将前面的234分割了呀,实际上不是的,"(?=2)3"这个正则匹配断言所在位置为2,但是后面却是3,所以永远匹配不到。
第四行解释了第三行的问题,断言当前所在位置为2,因此能匹配到234这个字符串。
第五行看懂了没,根据上面3、4两行的经验,这里不是表示能匹配23和93,而是仅仅能匹配 “2和一个空字符串(并且不包含2)” 这个结果,93是永远匹配不到的,因为(?=9)后面必须接9而断言后面却接了3;并且竖线“或关系”也不是按照我们头脑中思考的分成 “(?=2)3 or (?=9)3” 而是 “(?=2) or (?=9)3” ;所以只能匹配前者 "(?=2)"。
第六行指示了正确使用竖线的方式。如果是 /2|93/ ,那么结果就是2,2,93。
第七行和第八行展示了我们正确使用零宽断言分割的方法。
所以,总结来说,并非是bug,而只是我不太理解零宽断言而已,并且这里很容易跳进坑里面。
By the way,这么弄来,我需求实现的代码错了,应该这么写:
——所以,还是有必要求个甚解。
例如:
SQL = INNER JOIN Sale b ON 1=1 LEFT JOIN OutStock c ON 1=1 RIGHT JOIN BunissMan c ON 1=1
分割成:
["INNER JOIN Sale b ON 1=1 ","LEFT JOIN OutStock c ON 1=1 ","RIGHT JOIN BunissMan c ON 1=1 "]
还好理解吧?
实现的方式其实挺多,循环遍历分割、正则分割等等。
为了感觉高大上一点,决定了正则。
就是在实验的过程中,发现了一个奇异的现象。
本来想测试一下各种JOIN的匹配情况,于是采用正则表达式如下:
/(?=INNER)|(?=LEFT)|(?=RIGHT)|(?=FULL OUTER) JOIN/
采用match,没有匹配到我想要的东西,但是,split却出来了结果:
测试源码:
var SQL = 'INNER JOIN Sale b ON 1=1 LEFT JOIN OutStock c ON 1=1 RIGHT JOIN BusniessMan c ON 1=1 '; var RegExpStr = /(?=INNER)|(?=LEFT)|(?=RIGHT)|(?=FULL OUTER) JOIN/; var MatchAll = SQL.match(RegExpStr) console.log(MatchAll) var SplitArr = SQL.split(RegExpStr) console.log(SplitArr)
测试结果:
["", index: 0, input: "INNER JOIN Sale b ON 1=1 LEFT JOIN OutStock c ON 1=1 RIGHT JOIN BusniessMan c ON 1=1 "] ["INNER JOIN Sale b ON 1=1 ", "LEFT JOIN OutStock c ON 1=1 ", "RIGHT JOIN BusniessMan c ON 1=1 "]
着实让我又惊又喜。
喜的是,这个需求这么容易结束了。
惊的是,不知道这是怎么得到的结果。
在python里面测试了相同的零宽断言,发现是不能进行分割的。
本着研究的精神继续探索。
var SomeStr = '12345129345' console.log(SomeStr.split(/234/)) // ["1", "5129345"] console.log(SomeStr.split(/2(?=3)/)) // ["1", "345129345"] console.log(SomeStr.split(/(?=2)34/)) // ["12345129345"] console.log(SomeStr.split(/(?=2)234/)) // ["1", "5129345"] console.log(SomeStr.split(/(?=2)|(?=9)3/)) // ["1", "23451", "29345"] console.log(SomeStr.match(/(2|9)3/g)) // ["23", "93"] console.log(SomeStr.match(/(?=23)|(?=93)/g)) // ["", ""] console.log(SomeStr.split(/(?=23)|(?=93)/)) // ["1", "234512", "9345"]
分析一下:
第一行将234作为分隔符分割了,很好理解。
第二行使用了零宽断言,能匹配2后面紧接着是3的的“分隔符”,所以将前面的“2”作为分隔符,而后面的2接着9,不能分隔。
第三行一开始困惑了我,理论上应该能将前面的234分割了呀,实际上不是的,"(?=2)3"这个正则匹配断言所在位置为2,但是后面却是3,所以永远匹配不到。
第四行解释了第三行的问题,断言当前所在位置为2,因此能匹配到234这个字符串。
第五行看懂了没,根据上面3、4两行的经验,这里不是表示能匹配23和93,而是仅仅能匹配 “2和一个空字符串(并且不包含2)” 这个结果,93是永远匹配不到的,因为(?=9)后面必须接9而断言后面却接了3;并且竖线“或关系”也不是按照我们头脑中思考的分成 “(?=2)3 or (?=9)3” 而是 “(?=2) or (?=9)3” ;所以只能匹配前者 "(?=2)"。
第六行指示了正确使用竖线的方式。如果是 /2|93/ ,那么结果就是2,2,93。
第七行和第八行展示了我们正确使用零宽断言分割的方法。
所以,总结来说,并非是bug,而只是我不太理解零宽断言而已,并且这里很容易跳进坑里面。
By the way,这么弄来,我需求实现的代码错了,应该这么写:
var SQL = 'INNER JOIN Sale b ON 1=1 LEFT JOIN OutStock c ON 1=1 RIGHT JOIN BusniessMan c ON 1=1 '; var RegExpStr = /(?=INNER JOIN)|(?=LEFT JOIN)|(?=RIGHT JOIN)|(?=FULL OUTER JOIN)/; var SplitArr = SQL.split(RegExpStr) console.log(SplitArr)
——所以,还是有必要求个甚解。
相关文章推荐
- jsTree 的简单用法--异步加载和刷新数据
- javascript实例学习之一——联动下拉框
- JSP_004_Cookie介绍03—Cookie的domain(域)
- js刷新页面不回到顶部
- Respond.js在IE8失效原因分析
- js鼠标移动导航菜单出现下拉菜单
- javascript判断浏览器的版本
- javascript原生代码实现ajax请求
- Javascript 常用系统内置函数
- js中arguments的作用
- js正则函数中test和match的区别
- 《JS高程》引用类型学习笔记
- JS 面向对象之继承 -- 原型链
- javascript BOM与DOM介绍
- js中小数向上取整数,向下取整数,四舍五入取整数的实现。
- javascript函数与事件
- JSP_004_Cookie介绍02—Cookie的最大生命和Cookie的path
- mobiscroll.custom-2.17.0.min.js 破解版
- JS对象
- Javascript权威指南——第二章词法结构,第三章类型、值和变量,第四章表达式和运算符,第五章语句