日期:2014-05-16  浏览次数:20390 次

javascript 正则表达式细节问题

以前发过一些文章:

正则表达式的Javascript应用
Extjs 正则表达式的优雅应用 -1


近来再看mastering regular expressions 想到的一些有趣的正则表达式细节问题,首先看

1.一段程序

?

var regs=[/x*/g,/x*$/g,/^x*/g,/^x*$/g,/x*?/g,/^x*?/g,/x*?$/g,/^x*?$/g];
for(var i=0,reg=null;reg=regs[i++];){
 console.log("*************reg :" +reg.source);
 console.log("xx".replace(reg,"y"));
 console.log("xx".match(reg));
var m;
var j=0;

while((m=reg.exec("xx"))&&++j<5){
console.log(m[0]+" - "+reg.lastIndex)
//reg.lastIndex+=1
}
}

?

可以先想一下结果 ,下面为运行输出:

?

*************reg :x*
yy
["xx", ""]
xx - 2
- 2
- 2
- 2
*************reg :x*$
yy
["xx", ""]
xx - 2
- 2
- 2
- 2
*************reg :^x*
y
["xx"]
xx - 2
*************reg :^x*$
y
["xx"]
xx - 2
*************reg :x*?
yxyxy
["", "", ""]
- 0
- 0
- 0
- 0
*************reg :^x*?
yxx
[""]
- 0
- 0
- 0
- 0
*************reg :x*?$
yy
["xx", ""]
xx - 2
- 2
- 2
- 2
*************reg :^x*?$
y
["xx"]
xx - 2

?

?

其中涉及到了:

?

-1. Backtracking(回朔的概念): 对每个量词(quantifier)以及或(||),正则引擎必须做出一个决定,对于量词(*,+,?,{2,}),正则引擎必须决定是否要多匹配一些字符,而对于或(字符类[a-z]或简写\s,.除外)必须决定选择哪个分支。

每次引擎作出了一个选择,它都会记住其他可能的选项,如果这次匹配失败则会退回到上次做选择的量词或位置,并选择其他的选项继续进行匹配。

?

举例:(From High performance javascript)

?

?

0. * 量词可以匹配空,zero match


1.匹配分为位置(开头,字符间,结尾)与字符 两类,match 的所有匹配结果会多一些


2.replace g 时,当遇到空匹配 时在当前位置(开头,字符间,结尾)匹配成功,正则引擎会强行bump-along到下一匹配处 (防止空匹配死循环匹配)


这解释了 /x*?/g 的交替情况


3.为了达到正则表达式整体匹配,后面的表达式会驱动前面的表达式回朔 对于前面为x*


x* 会迫使量词匹配次减 1 ,直到为空匹配则这时一定成功


这解释了 /x*/ ,/x*$/ 一次匹配 xx ,二次到结尾位置空匹配,但是注意? /x*/ 并不包括开头位置^匹配,x*为贪婪匹配,开头位置不能满足,但是bump后,第一个x可以满足,所以无须匹配开头,直接匹配到 xx全部,但是第二次只剩下空字符串,为了匹配成功,才选择了空匹配,可见:

?

"xx".replace(/y*/g,"y")
?


对于前面为 x*?


x*? 会迫使量词增1,直到当前字符不能匹配x位置


这解释了 /x*?$/为了取得 在第一个 x处,为了达到匹配,扩展到 匹配 xx的情况,在第二次空字符串时,就默认0匹配成功了。

?

5.Regexp.lastIndex 为 the position of