分组类型
有四种分组类型
- 捕获型
()
- 非捕获型
(?:)
- 正向前瞻型
(?=)
- 反向前瞻型
(?!)
捕获型
- 分组
下面的正则表达式匹配dotdotdot
/dotdotdot/
更优雅的写法是将其分组,由一对圆括号包裹的小整体称为分组
/(dot){3}/
- 候选
一个分组中可以有多个候选表达式,用|
分隔,|
意为“或”
var reg = /I love (apple|orange|banana)/
reg.test('I love apple')//true
reg.test('I love orange')//true
reg.test('I love banana')//true
reg.test('I love popcorn')//false
- 捕获与引用
被正则表达式匹配到的字符串会被暂存起来,其中分组捕获的串从1开始编号,$1表示第一个被捕获的串,$2是第二个,以此类推,我们可以引用这些串。
var reg = /(\d{4})-(\d{2})-(\d{2})/
var data = '2017-10-24'
reg.test(data)
RegExp.$1//2017
RegExp.$2//10
RegExp.$3//24
- 与replace配合
String.prototype.replace
方法的传参中可以直接引用被捕获的串。比如我们想将日期10.24/2017改为2017-10-24
var reg = /(\d{2})\.(\d{2})\/(\d{4})/
var data = '10.24/2017'
data = data.replace(reg, '$3-$1-$2')
console.log(data)//2017-10-24
给replace传递迭代函数可以优雅地解决一些问题
将违禁词转换为等字数的星号是一个常见的需求,比如文本是dot is a doubi
,其中dot
和doubi
是违禁词,转换后应为*** is a *****
var reg = /(dot|doubi)/g
var str = 'dot is a doubi'
str = str.replace(reg, function (word) {
return word.replace(/./g, '*')
})
console.log(str)//*** is a *****
replace与正则捕获组匹配还有一个常见用法,将浮点数左边的数从右向左每三位添加一个逗号
function commafy(num) {
return num.toString().replace(/(\d)(?=(\d{3})+\.)/g, function ($2) {
return $2 + ','
})
}
console.log(commafy(1200000000.11))//1,200,000,000.11
console.log(commafy(123246723749.213769283))//123,246,723,749.21378
其中正则表达式部分如下,/(\d)(?=(\d{3})+\.)/g
匹配全局中,数字后面跟随的是(以.
结尾的、三个数字的分组至少有一组)的串
- 嵌套分组的捕获
如果碰到类似/((dot) is (a (doubi)))/
这种嵌套分组,捕获的顺序是什么呢?
var reg = /((dot) is (a (doubi)))/
var str = 'dot is a doubi'
reg.test(str)//true
console.log(RegExp.$1)//dot is a doubi
console.log(RegExp.$2)//dot
console.log(RegExp.$3)//a doubi
console.log(RegExp.$4)//doubi
从以上结果可看出,规则是以左括号出现的顺序进行捕获。
- 反向引用
正则表达式里可以进行反向引用
var reg = /(\w{3}) is \1/
console.log(reg.test('dot is dot'))//true
console.log(reg.test('dolby is dolby'))//false
console.log(reg.test('dot is tod'))//false
console.log(reg.test('dolby is dlboy'))//false
\1
引用了第一个被分组所捕获的串,本例中即(\w{3})
,表达式是动态决定的,如果编号越界了会被当成普通的表达式
var reg = /(\w{3}) is \3/
console.log(reg.test('dot is \3'))//true
console.log(reg.test('dolby is dolby'))//false
非捕获型分组
有时我们只是想分个组,并没有捕获的需求,这种情况下可以使用非捕获性分组,语法为(?:
var reg = /(?:\d{4})-(\d{2})-(\d{2})/
var date = '2017-10-24'
console.log(reg.test(date))//true
console.log(RegExp.$1)//10
console.log(RegExp.$2)//24
这个例子中,(?:\d{4})
分组不会捕获任何串,所以$1为(\d{2})
捕获的串
正向与反向前瞻型分组
但看名称概念有些模糊不清,可以理解为肯定表达式与否定表达式,前瞻型分组也不会捕获值
- 正向前瞻
var reg = /dot is a (?=doubi)/
console.log(reg.test('dot is a doubi'))//true
console.log(reg.test('dot is a shadou'))//false
dot is a
后面要跟上doubi
才匹配成功
- 反向前瞻
var reg = /dot is a (?!doubi)/
console.log(reg.test('dot is a doubi'))//false
console.log(reg.test('dot is a shadou'))//true
dot is a
后面除了跟上doubi
,都能匹配成功
前瞻型分组与非捕获型都不会捕获值,那么它们的区别是什么?
var str = 'dot is a doubi'
var reg = /dot is a (?:doubi)/
console.log(reg.test(str))//true
console.log(RegExp.$1)//无结果
reg = /dot is a (?=doubi)/
console.log(reg.test(str))//true
console.log(RegExp.$1)//无结果
reg = /(dot is a (?:doubi))/
console.log(reg.test(str))//true
console.log(RegExp.$1)//dot is a doubi
reg = /(dot is a (?=doubi))/
console.log(reg.test(str))//true
console.log(RegExp.$1)//dot is a
可以看出,非捕获型分组匹配到的串仍会被外层的捕获型分组捕获到,但前瞻型却不会,当你需要参考后面的值,又不想连它一起捕获时,前瞻型分组就派上用场了
关于正则表达式,更多请见我的博客