发博文
正文 字体大小:

有关正则表达式中非捕获组的网上总结和个人见解

(2010-11-04 15:54:03)
标签:

捕获

正则表达式

字符串

元素

分类: 技术

(以下问题及解答一、解答二可参考:http://www.39g.com/html/271/277/2010/09/912511323682.htm

 

问题:

看到7.3.4 非捕获性分组这里,书上说非捕获性分组不会创建反向引用,下面是例子:
var sToMatch = "#123456789";

var reNumbers = /#(?:\d+)/;

reNumbers.test(sToMatch);

alert(RegExp.$1);

这里alert输出是空的。

var sToMatch = "en-us rv:0.9.4";

var reNumbers = /rv:(\d+\.\d+(?:\.\d+)?)/;

var result = reNumbers.test(sToMatch);

alert(RegExp.$1);

这里alert输出就成了0.9.4。

最后那个.4是非捕获性分组捕获到的。这里就奇怪了,为什么前面的非捕获性分组不能捕获,而嵌套的非捕获性分组就又可以捕获了?而且这里好像不用非捕获性分组照样可以达到相同的目的,为什么要用非捕获性分组呢?

 

解答一: 

    因为RegExp.$1取的是第一个捕获组而且.4包含在第一个捕获组中,所以取RegExp.$1时可以取到。而.4所在的第二个组是非捕获组,当取RegExp.$2的时候.4是取不到的。

    如果改成:var reNumbers = /rv:(\d+\.\d+(\.\d+)?)/;则RegExp.$2是.4。上面问题中的(?:\.\d+)是非捕获组,内存不会保存你取到的值。所以RegexExp的组中应该就没有$2这一个值。RegExp.$2取到的是空的。
    反向引用的时候(\d+\.\d+(?:\.\d+)?)--\1 这里是反向引用第一个捕获组,匹配--前后都一样的字符串。而(\d+\.\d+(?:\.\d+)?)--\2 是有错误的,因为第二个组是非捕获的,内存上就没有第二个组的内容,所以引用失败。

解答二:
    要了解非捕获组就要先了解捕获组,之后再了解为什么会有非捕获组的出现。简单点说,捕获组就是把()中匹配到的内容保存到一个按“(”出现的顺序编号的组里,以供后续引用,引用的方式有反向引用,或是RegExp.$number等方式,不同的语言,支持的引用方式不同。
    只要使用了(),默认为使用了捕获组,而这就带来一个问题,有些场景不得不使用(),但又不关心它匹配到的内容,比如写一个匹配24小时制HH:mm:ss的时间的正则如下:([01][0-9]|2[0-3])(:([0-5][0-9])){2},通常关心的只是整体的时间,并不关心局部的内容,这样就产生了一种副作用,将不关心的内容单独保存到内存中,只会浪费资源,降低效率。非捕获组就是为了抵消这一副作用来产生的,非捕获组只参与匹配,但不会把匹配到的内容捕获到组里。所以非捕获组根本就不参与编号,也就无从谈起它对应哪个$number。在取不存在的编号的捕获组时,有些语言会返回空字符串,有些语言会报异常。
    (\d+\.\d+(?:\.\d+)?)中,整体是一个捕获组,按“(”出现的顺序,编号为1,(?:\.\d+)虽然是非捕获组,也是要参与匹配的,只是不将匹配结果单独保存到组里而已。
    还需要说明的是,在绝大多数语言中,正则表达式整体对应的是$0,捕获组的编号是从1开始的。

 

本人见解:

    本人在网上看到这个问题以及相关解答后,把所有的答案总结了一下,分成这两类。本人倾向于解答二,认为非捕获组不参与编号,没有对应的$number,也就肯定取不到值了。在取不存在的编号的捕获组时,有些语言会返回空字符串,有些语言会报异常。

    本人为此试验了一下,在flashdevelop下编译代码:

    var re:RegExp = /(i|you|he|she|it|we|they) likes? to (\w+)/i;    //标示为句M

    var match:Object = re.exec("We like to party.");
    trace(match);     //标示为句N

    结果返回:We like to party,We,party(从显示结果可以看出match中含有三个元素,用','隔开)


    然后把句M改成:var re:RegExp = /(i|you|he|she|it|we|they) likes? to (?:\w+)/i; 

    结果返回:We like to party,We(此时match中只含有两个元素了)

    然后把句N改成:trace(match[2]);

    结果返回:undefined(说明match中第三个元素没有定义)

 

    然后把句M改成:var re:RegExp = /(?:i|you|he|she|it|we|they) likes? to (?:\w+)/i; 

    结果返回:We like to party(此时match中只含有一个元素了)

    然后把句N改成:trace(match[1]);

    结果返回:undefined(说明match中第二个元素没有定义)

 

    从上述实验结果来看,非捕获组确实不参与编号,不在内存保存。并且在flashdevelop中如果非法访问不存在的元素,不会报异常,但是会显示undefined(这只是flashdevelop的效果,其他软件是报错还是怎么我就不知道了。)

阅读 评论 收藏 转载 打印举报
已投稿到:
  • 评论加载中,请稍候...

       

    验证码: 请点击后输入验证码 收听验证码

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 不良信息反馈 电话:4006900000 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有