正则捕获组

作者: _Dot912 | 来源:发表于2017-10-24 17:06 被阅读0次

    分组类型

    有四种分组类型

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

    捕获型

    • 分组
      下面的正则表达式匹配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
    

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

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

    相关文章

      网友评论

        本文标题:正则捕获组

        本文链接:https://www.haomeiwen.com/subject/iqfxpxtx.html