正则表达式第三回--模式、分组与前瞻
贪婪的正则
正则是默认贪婪的,它会尽可能多的匹配,我想这是一个大家都知道的事实。 经典例子:
'12345678'.replace(/\d{3,7}/g, '#')
// 输出: #8
可以看到,规则是匹配3~7个数字,由于正则默认是贪婪模式,匹配了最大数量7个;
如果我们希望它尽可能少的匹配,也就是说一旦匹配成功就不继续匹配了,只需要在量词后面加个问号即可。
'12345678'.replace(/\d{3,7}?/g, '#')
// 输出: ##78
分组
我们知道,量词是作用于紧挨着它的那个元字符或原义文本字符或分组的。
'a1b2c3d4'.replace(/[a-z]\d{3}/g, "#")
// 输出: a1b2c3d4
上面这个示例中,我们本来试图匹配一个小写英文字母加数字连续出现3次的场景,把它换成#
,但是事与愿违,规则与字符串并没有匹配上。实际上,紧挨着量词{3}
的是一个元字符\d
,所以这里的意思是:匹配数字连续出现三次。
如果要准确匹配我们的初始想法,可以给这个组合加上分组,修改后如下:
'a1b2c3d4'.replace(/([a-z]\d){3}/g, "#")
// 输出: #d4
当然,分组的魅力不在这里,分组的最大魅力在于分组引用,在repalce函数的第二个参数中,可以直接在字符串
神奇的"或"
或的写法是|
,正则的或是单竖杠,JS中逻辑符号的或是双竖杠,这点需要注意。
或符号|
在没有碰到分组边界的时候会把正则表达式“切割”成好几段,在遇到分组边界时则停止,比如/Lady|Gaga/
表示匹配单词Lady
或Gaga
。
"LadyGaga".replace(/Lady|Gaga/g, '#');
// 输出: ##
注意:或字符两边不要留空格,写成
/Lady | Gaga/
这样,因为这里的空格也属于原义文本字符。
当然,一开始我们也提到了,在遇到分组边界符时,或字符就“割”不动了,会停下来。这种情况比较少。
有前瞻,没有后顾
所谓前瞻,就是当匹配到符合正则的内容时,向前检查前面的内容是否符合断言部分。
断言这个概念是什么意思呢?它可以在里面书写一切的正则表达式,形式为(?=我们写的正则规则)
,但和普通的正则表达式不同的是:它不算作正式规则的一部分,只作为一种我们定义规则的辅助规则。举个栗子就明白了:
"my love, my heart".replace(/my\slove/g, '#');
// 正常书写正则,输出为 #, my heart
"my love, my heart".replace(/my(?=\slove)/g, '#');
// 用断言书写后面的空格加love,输出 # love, my heart
// 断言内的空格加love并没有随my一起被替换掉
原来这特么就叫断言啊。
注意一下前瞻的方向,因为字符串的匹配是从左到右,所以向前,也就是向右。