猫窝私语 — Makumo's Blog

玛酷猫的温馨小窝,记录生活点点滴滴。

@玛酷猫12 年前

08/21
16:18
JS&JQUERY

正则表达式中的反向引用

今天群里有人抛出一个正则求分析,如下:

^(?:(?!\d{4}).)*(\d{4})(?:(?!\1).)*\1

咋一看,整句全都是特殊符号,头晕中。不过正则表达式都是看起来晕,慢慢分析起来还是蛮有意思。里面有两天稍微复杂点,一个是断言,这个之前写过一篇文章介绍《正则表达式中的断言和非捕捉组》,另外一个就是反向引用,这个以前遇到的少,遇到不怕,搜索一下就好了。一下引用百度百科:

正则表达式的最重要功能之一是存储匹配的模式的一部分以供以后重新使用的能力。您可能想起,若在正则表达式模式或模式的一部分两侧加上括号,就会导致表达式的一部分被存储到临时缓冲区中。可以通过使用非捕获元字符 ?:、?= 或 ?! 来重写捕获。
反向引用
每个捕获的子匹配项按照它们在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。可以使用 \n来访问每个缓冲区,其中n 是标识特定缓冲区的一位或两位十进制数字。

清楚这个,上面那个就好分析了。借助Regex Match Tracer试着分析如下:

^边界开头条件,(?!\d{4}). 负向零宽度断言,意思断言自身位置的后面不能匹配四位数字,也就是开头到第一组四位数字为止,(?:(?!\d{4}).)*非捕捉组,不进行捕捉组记录。(\d{4}),第一个捕捉组,4位数字。\1反向引用,也就是前面第一个捕捉组所捕捉到的4位数字,(?!\1).,和前面的负向零宽度断言相同,意思断言自身位置的后面不能匹配第一个捕捉组的四位数字,这之间可以出现其他的数字组合。(?:(?!\1).)*非捕捉组,最后再跟一个\1,也就是第一捕捉组的那4位数字。

整体意思大概就是:从开始遇到第一个4位数字。继续,当遇到第二次同样的4位数字后截止,匹配这部分内容。

另外还有一点需要注意,就是反向引用如果后面要加数字,例如\10,不同的引擎会有不同的解释:在.NET中,这里的“\10”被解析成第10个捕获组的反向引用,但如果正则表达式加了RegexOptions.ECMAScript参数,则这里的“\10”被解析成第1个捕获组的反向引用加一个普通字符“0”;而在JavaScript中,在IE的浏览器引擎中,“\10”被解析成第1个捕获组的反向引用加一个普通字符“0”,而在Firefox、Opera等浏览器中,得到的结果为空,说明“\10”被解析成第10个捕获组的反向引用。为了防止这种情况,后面跟的数字一般用非捕捉组代替,例如:\1(?:0)表示。

本人正则表达式并不是很熟练,如有问题,欢迎指正。

正则表达式中的反向引用