04捕获
正则捕获: 把一个字符串中和正则匹配的部分获取到
方法:
[正则] exec test [字符串] replace split match
基于exec可以实现正则的捕获
- 如果当前正则和字符串不匹配,捕获的结果是null
- 如果匹配,捕获的结果是一个数组 0: 大正则捕获的内容 index: 正则捕获的起始索引 input: 原始操作的字符串
- 执行一次exec只能捕获到第一个和正则匹配的内容,其余匹配内容没捕获到(正则捕获有懒惰性)
解决正则捕获的懒惰性,需要加全局修饰符g
编写一个 捕获所有匹配的方法
js
RegExp.prototype._execAll = function(str) {
// 为防止出现死循环,检查一下正则是否有 g,没有只把第一次捕获的结果返回
if (!this.global) return this.exec(str)
let ret = []
let valArr = this.exec(str)
while (valArr) {
// 或者用 this.lastIndex < str.length来判断
// 把每次捕获到的结果(数组)的第一项 存储到ret中
ret.push(valArr[0])
valArr = this.exec(str)
}
return ret
}其实 match 也就是上面的方法的实现
分组捕获
在正则捕获时,如果存在分组,捕获时匹配大正则字符,且还会把小分组匹配内容也拿到
?: 可以阻止分组捕获 (合理使用提高正捕获性能)
正则捕获还具有贪婪性,每一次捕获时,总是捕获和正则匹配中最长的内容
阻止贪婪捕获 \d+? 加个 ?即可 (把问号放到量词元字符后面,取消捕获的贪婪性)
? 问号在正则中的作用
- 量词元字符 出现 0 次或 1 次 /a?/ a出现1次或不出现
- 取消正则捕获的贪婪性 /\d+?/ 捕获时只捕获最短的内容
- 只匹配不捕获 /?😕
- ?= 正向预查
- ?! 负向预查
test匹配也相当于捕获,修改了lastIndex的值 。
坑:
js
let str = 'hello2018'
let reg = /\d+/g
if (reg.test(str)) {
console.log(reg.exec(str)) // null
}虽然捕获的不是同一个字符串,但正则是同一个时. 上次正则处理时修改了它的lastIndex 所以会对下一次匹配的新字符串产生影响
js
let str = 'hello2018'
let reg = /\d+/g
console.log(reg.exec(str)) // ['2018' ... ]
console.log(reg.exec('hello2018world666')) // ['666' ...]RegExp.$1 把上一次匹配 test/exec 到的结果获取到,获取的是第一个小分组匹配的内容,大正则匹配的内容无法获取。 这是一个全局的值,浏览器中$1只有一个,其他正则操作会覆盖该值,所以这种方式没实际用处。
replace 实现正则捕获的方法 (本身是字符串的替换方法)
js
let str = 'newA2018newB0606'
str = str.replace('new', 'newT')
// str -> "newTA2018newB0606"
str = str.replace('new', 'newT')
// str -> "newTTA2018newB0606"
str = 'newA2018newB0606'
str = str.replace(/new/g, 'N')
// str -> "NA2018NB0606"用reg正则和str字符串进行匹配,匹配几次就替换几次,每一次都是把当前大正则匹配的结果用第二个传递的字符串替换掉
js
let str = 'hello{val:2018}world{val:2019}'
let reg = /\{val:(\d+)\}/g
str = str.replace(reg, '@')
// str -> "hello@world@"
str = 'hello{val:2018}world{val:2019}'
// $1不是拿这个字符串替换掉大正则匹配的内容
// 此处的$1代表第一个分组匹配的内容,等价于 RegExp.$1
str = str.replace(reg, '$1')
// str -> "hello2018world2019"- reg和str匹配多次,函数就会被触发多少次,而且传递了一些参数值
- 每一次arg中存储的信息,和执行exec捕获的信息相似 (内置原理:每一次正则匹配到结果,都把函数执行,然后基于exec把本次匹配的信息捕获到,然后把捕获的信息传递给这个函数)
- 每一次函数中返回是什么,就把当前大正则匹配的内容替换成什么
js
let str = 'hello{val:2018}world{val:2019}'
let reg = /\{val:(\d+)\}/g
str = str.replace(reg, (...arg) => {
console.log(arg)
return ''
})
// ["{val:2018}", "2018", 5, "hello{val:2018}world{val:2019}"]
// ["{val:2019}", "2019", 20, "hello{val:2018}world{val:2019}"]
// "helloundefinedworldundefined"