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 the first character after the match,但是使用 exec 时遇到结尾空匹配并不会像 replace一样会强行驱动,对*量词连续使用 exec 会造成死循环,同java不同,java 连续find遇到结尾空匹配会自动bump的:
?
import java.util.regex.Matcher;import java.util.regex.Pattern;public class Test { public static void main(String[] args) throws Exception { Pattern p = Pattern.compile("x*"); Matcher m = p.matcher("xx"); while (m.find()) { System.out.println("match : "+m.group()); } System.out.println("xx".replaceAll("x*","y")); }}?
2. 多行模式问题:?
?
"1\n\n2\n3".replace(/^.*$/mg,"m"); // m\nm\nm\nm\n?
^ : 匹配于当前整串头位置,或者 \n 后一个位置,相当于(?<=\n),js不支持
$ : 匹配于整串结尾位置,或者 \n 前一个位置,相当于(?=\n)
. : javascript中不会匹配 \n ,不可设置多行模式,则要匹配到 换行则要手动匹配
若要匹配任何字符则要使用:[\d\D],[\s\S],[\w\W],[\0-\uffff] 以及(?:.|\r|\n|\u2028|\u2029) 尽量用 character class少用 alteration
行缩减应用:
?
"1\n\n2\n3".replace(/^.*$\n?/mg,"m"); //mmmm?
?
2010-09-20 update :
备忘,强大的 jquery 正则式整理报告
?
?
?
1 楼 xiongzhijian51 2010-01-20 难得楼主能沉下心来钻研,真的佩服你.