我的代码类似于对象数组中的此过滤条目:
var filterRegex = new RegExp(".*blah.*","ig"); if (filterRegex.test(events[i].thing) && events[i].show) { console.log("SUCCESS: filtering thing " + i + " " + events[i].thing); events[i].show = false; numevents--; }
我得到的结果与if if条件不一致(用Firebug检查,两个条件都是单独的,但有时整个表达式的计算结果为false).但是,如果我实际上alert()
在这个if语句中放入一个调用(如第4行),它会变得一致,我得到我想要的结果.
你能看出这个逻辑有什么问题,并告诉我为什么它并不总能产生预期的东西?
好的,我现在看到了.你的问题的关键是使用g
(全局匹配)标志:当为正则表达式指定它时,它将被设置为可以多次执行,每次从它上次停止的地方开始.它在其lastIndex
属性中保留了各种"书签" :
var testRegex = /blah/ig; // logs: true 4 console.log(testRegex.test("blah blah"), testRegex.lastIndex); // logs: true 9 console.log(testRegex.test("blah blah"), testRegex.lastIndex); // logs: false 0 console.log(testRegex.test("blah blah"), testRegex.lastIndex);
上面的例子创建了一个非常简单的正则表达式的实例:它匹配"blah",大写或小写,字符串中的任何位置,并且可以多次匹配(g
标志).在第一次运行时,它匹配第一个"blah",并将叶子lastIndex
设置为4(第一个"blah"之后的空格索引).第二次运行开始匹配lastIndex
,匹配第二个blah,并将叶子lastIndex
设置为9 - 一个超过数组末尾.第三次运行不匹配 - lastIndex
是伪造的 - 并且叶子lastIndex
设置为0.因此,第四次运行与第一次运行具有相同的结果.
现在,你的表达比我的贪婪得多:它会在"blah"之前或之后匹配任意数量的任何字符.因此,无论你测试什么字符串,如果它包含"blah",它将始终匹配整个字符串并将lastIndex
set设置为刚测试的字符串的长度.意思是,如果要调用test()
两次,第二次测试将始终失败:
var filterRegex = /.*blah.*/ig; // logs: true, 9 console.log(filterRegex.test("blah blah"), filterRegex.lastIndex); // logs: false, 0 console.log(filterRegex.test("blah blah"), filterRegex.lastIndex);
幸运的是,由于您在调用之前立即创建了正则表达式test()
,并且从不调用test()
过多次,因此您将永远不会遇到意外行为... 除非您使用的调试器允许您添加另一个调用test()
.对.在Firebug运行时,包含您的调用的监视表达式test()
将导致在false
您的代码或监视结果中出现间歇性结果,具体取决于首先获取它的位置.让你慢慢疯了......
当然,没有g标志,livin'很容易:
var filterRegex = /.*blah.*/i; // logs: true, 0 console.log(filterRegex.test("blah blah"), filterRegex.lastIndex); // logs: true, 0 console.log(filterRegex.test("blah blah"), filterRegex.lastIndex);
不需要时避免使用全局标志.
注意在调试器中评估的内容:如果有副作用,它可能会影响程序的行为.