正则捕获组

分组类型

有四种分组类型

  • 捕获型()
  • 非捕获型(?:)
  • 正向前瞻型(?=)
  • 反向前瞻型(?!)

捕获型

  • 分组
    下面的正则表达式匹配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,其中dotdoubi是违禁词,转换后应为*** 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

可以看出,非捕获型分组匹配到的串仍会被外层的捕获型分组捕获到,但前瞻型却不会,当你需要参考后面的值,又不想连它一起捕获时,前瞻型分组就派上用场了

关于正则表达式,更多请见我的博客

你可能感兴趣的:(正则捕获组)