【0基础教程】Javascript 里的分组正则Capturing Groups使用方法及原理

【0基础教程】Javascript 里的分组正则Capturing Groups使用方法及原理_第1张图片

一、从最简单开始

现有一个字符串: “1-apple”
需要提取出 1 和 apple 来,对应的正则表达式很简单: ^(\d)-(.+)$
对应的代码也比较简单:

        const str = "1-apple"
        const regexp = /^(\d)-(.+)$/
        let match = regexp.exec(str)
        console.log(match[0])
        console.log(match[1])
        console.log(match[2])

其中,match[1]和match[2]是我们想要的结果,分别是 ‘1’ 和 ‘apple’ ,
而 match[0] 一般来说没什么用,它相当于一个完整匹配,值是 ‘1-apple’ 。


二、分组正则

所谓“分组”,就是比如这种情况:
1-apple
2-orange
3-pear
需要正则的内容不止一行,和上例相比,其对应的正则表达式基本一样,但是后面必须加上gm标识符,
(g代表global,m代表multi line),代码如下:

        const str = "1-apple\n2-orange\n3-pear"
        const regexp = /^(\d)-(.+)$/gm   //注意:和上例相比,唯一的区别是后面加了gm标志
        let match = regexp.exec(str)
        console.log(match[0])
        console.log(match[1])
        console.log(match[2])

直接运行代码,发现只解析了1-apple出来,后两行无效,这是为啥?
让我们修改一下代码:

        const str = "1-apple\n2-orange\n3-pear"
        const regexp = /^(\d)-(.+)$/gm  
        let match
        match = regexp.exec(str)
        console.log('index = ', match.index)
        console.log('result = ', match)
        match = regexp.exec(str)
        console.log('index = ', match.index)
        console.log('result = ', match)
        match = regexp.exec(str)
        console.log('index = ', match.index)
        console.log('result = ', match)

在这个例子里,我们连续三次触发了match = regexp.exec(str) 这行语句,
事实上,尽管语句完全一样,但是每一次match的返回值都不同。在分组正则的时候,.exec方法总是会将当前匹配值的首字符位置保存在index变量里,当下一次触发.exec的时候,index并不会从0开始搜索,而是从第一次匹配完成之后的位置进行第二次匹配,如此反复,直至将整个字符匹配完成为止。

知道了 .exec 这个方法可以反复执行这个小秘密之后,将代码再改改就很简单了:

        const str = "1-apple\n2-orange\n3-pear"
        const regexp = /^(\d)-(.+)$/gm   //注意:和上例相比,唯一的区别是后面加了gm标志
        let match
        while ((match = regexp.exec(str)) !== null) {
            console.log('index = ', match.index)
            console.log('result = ', match)
        }

三、matchAll 登场

如果你不喜欢while循环方式,还可以使用 matchAll ,就可以不必使用 while 循环加 exec 方式。使用 matchAll 会得到一个迭代器的返回值,配合 for…of, array spread, 或者 Array.from() 可以更方便实现功能。

        const str = "1-apple\n2-orange\n3-pear"
        const regexp = /^(\d)-(.+)$/gm

        const matches = str.matchAll(regexp) // 采用matchAll进行匹配

        for (const match of matches) { // 采用 for of 方式读取
            console.log('index = ', match.index)
            console.log('result = ', match)
        }

这段代码效果和上例完全一样, 也可以用Array.from() 实现同样的效果:

        const str = "1-apple\n2-orange\n3-pear"
        const regexp = /^(\d)-(.+)$/gm

        const matches = str.matchAll(regexp) 
        Array.from(str.matchAll(regexp), (match) => { // 采用 Array.from方式读取
            console.log('index = ', match.index)
            console.log('result = ', match)
        })

或者更简单的ES6的“三个点”语法( array spread ):

        const str = "1-apple\n2-orange\n3-pear"
        const regexp = /^(\d)-(.+)$/gm

        const matches = [...str.matchAll(regexp)] // 采用 ... 方式展开str.matchAll(regexp)

        console.log(matches[0][1]) // 显示:1
        console.log(matches[0][2]) // 显示:apple
        console.log(matches[1][1]) // 显示:2
        console.log(matches[1][2]) // 显示:orange

三个点称为 “array spread” 或者“展开语法”,它的作用很多很杂,没有展开语法的时候,只能组合使用 push, splice, concat 等方法,来将已有数组元素变成新数组的一部分。有了展开语法,通过字面量方式,构造新数组会变得更简单、更优雅:

var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];
// ["head", "shoulders", "knees", "and", "toes"]

四、后记

本文只列举了非常简单的关于正则分组的基础案例,进一步研究可以阅读以下资料:

【matchAll()详解】:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll

【array spread 展开语法详解】:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_syntax

你可能感兴趣的:(javascript,开发语言,ecmascript)