持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情
前言
当使用正则表达式从字符串中提取特定信息时,通常会面临一个问题,那就是提取出来的字符串代表着什么?
关于这一点,除了开发者之外,其他人员如果想要知道,难免需要联合上下文进行推导才能知道,比较浪费时间。
那么是否可以给正则表达式的提取部分命名呢?答案是可以的。
具名捕获组
在 JS
中,允许给捕获信息命名,方便捕获时提取。
假设有以下测试案例:
const reg = /My name is ([^!]+), ([0-9]+) years old !/
const text = 'My name is Bear white, 18 years old !'
// 通过 match 捕获
const catchGroups = text.match(reg)
可以看到,如果想要获取捕获的信息,只能使用 catchGroups[1]
、catchGroups[2]
这种读取数组的写法进行获取,写在代码中,其他人员很难知道这两个捕获的信息代表着什么?
如果加上命名,就可以通过 groups
属性直接获取具体捕获名称以及信息:
// 正则表达式添加捕获名称
const reg = /My name is (?<name>[^!]+), (?<age>[0-9]+) years old !/
const text = 'My name is Bear white, 18 years old !'
const catchGroups = text.match(reg)
// 打印捕获组信息
console.log('catchGroups:', catchGroups.groups)
可以看到,在正则表达式中 catchGroups
多了一个 groups
信息,里面分别是捕获的 name
和 age
。
使用方法
使用时也是十分简单,格式是以问号 ?
开头,后续的<>
里面加上捕获名称,最后在 ()
里面写上捕获表达式即可,完整写法: ?<捕获名称>(捕获表单式)
。
在上面的例子中,也是在捕获name
和 age
的表达式前面加上 ?<name>
和 ?<age>
而已。
然后当使用 RegExp.prototype.exec() 或者是 String.prototype.match(),它们的返回结果会添加一个 groups
属性,里面一个 json
对象,键名是捕获的名称,键值是捕获的值,参考上面捕获组的打印信息。
如果使用 String.prototype.replace(),第二个参数也是可以使用捕获名称的,代码如下:
// 直接使用捕获名称获取值
const replaceValue_1 = text.replace(reg, '$<age> - $<name>')
// 如果是函数,则参数的最后一项是捕获组
const replaceValue_2 = text.replace(reg, (...arg) => {
const { name, age } = arg[arg.length - 1]
return `${name} - ${age}`
})
console.log('replaceValue_1:', replaceValue_1)
// replaceValue_1: 18 - Bear white
console.log('replaceValue_2:', replaceValue_2)
// replaceValue_2: Bear white - 18
注意
如果是使用 String.prototype.match() 进行捕获,则正则表达式不能加上 g
的全局匹配后缀,不然命名组的功能会失效。
同样也不能使用 String.prototype.matchAll()。