当前位置: 代码迷 >> JavaScript >> javascript 正则表达式细节有关问题
  详细解决方案

javascript 正则表达式细节有关问题

热度:271   发布时间:2012-11-23 22:54:33.0
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  
难得楼主能沉下心来钻研,真的佩服你.