1 实现正则捕获的方法
- 正则RegExp.prototype方法
- exec: 一个在字符串中执行查找匹配的RegExp方法,它返回一个数组(未匹配到则返回 null)。
- test: 一个在字符串中测试是否匹配的RegExp方法,它返回 true 或 false。
- 字符串String.prototype方法
- replace: 一个在字符串中执行查找匹配的String方法,并且使用替换字符串替换掉匹配到的子字符串。
- match: 一个在字符串中执行查找匹配的String方法,它返回一个数组,在未匹配到时会返回 null。
- matchAll: 一个在字符串中执行查找所有匹配的String方法,它返回一个迭代器(iterator)。
- split: 一个使用正则表达式或者一个固定字符串分隔一个字符串,并将分隔后的子字符串存储到数组中的
String
方法。 - search: 一个在字符串中测试匹配的String方法,它返回匹配到的位置索引,或者在失败时返回-1。
2. 方法解析
2.1 exec方法
正则捕获的懒惰性: 默认只捕获第一个
// 例
let str = 'sdfsadf12354asdfas412456aasdf';
let reg = /\d+/; // 捕获的正则表达式需要能过验证通过捕获对象字符串的
console.log(reg.exec(str)); // => ["12354", index: 7, input: "sdfsadf12354asdfas412456aasdf", groups: undefined]
/*
* 结果:
* 1. 捕获到的结果是null(正则验证false) 或者一个数组
* 第一项: 本次捕获到的内容
* 其余项: 对应小分组本次单独捕获的内容
* index: 当前捕获内容在字符串中的起始索引
* input: 原始字符串
* 2. 每执行一次exec, 只能捕获到一个符合正则规则的 => 称之为'正则捕获的懒惰性': 默认只捕获第一个
*/
**懒惰性捕获的原因: **
- 懒惰性捕获的原因: 默认情况下lastIndex的值不会被修改, 每一次都是从字符串开始位置查找, 所以找到的元素永远只是第一个
解决方法:
- 设置全局匹配修饰符g后, 会自动修正lastIndex的值(手动修改是无用的)
// 例
let str = 'sdfsadf12354asdfas412456aasdf';
let reg = /\d+/g; // 捕获的正则表达式需要能过验证通过捕获对象字符串的
/*
* reg.lastIndex: 当前正则下一次匹配的起始索引位置
* 懒惰性捕获的原因: 默认情况下lastIndex的值不会被修改, 每一次都是从字符串开始位置查找, 所以找到的元素永远只是第一个
* 直接修改lastIndex的值是无效的
* 通过设置全局匹配修饰符g, 会自动修正lastIndex的值
*/
console.log(reg.exec(str)); // => ["12354", index: 7, input: "sdfsadf12354asdfas412456aasdf", groups: undefined]
console.log(reg.exec(str));// => ["412456", index: 18, input: "sdfsadf12354asdfas412456aasdf", groups: undefined]
console.log(reg.exec(str));// => null 当全部捕获后, 再次捕获的结果是null, 但是lastIndex又回归了初始值0, 再次捕获时又会从头开始
2.2 test方法
test方法也会捕获, 但是不会返回捕获结果
-
若是设置了全局修复符g, 使用test方法时会将lastIndex调整为下一个捕获的lastIndex
// 例 let str = 'sdfsadf12354asdfas412456aasdf'; let reg = /\d+/g; // 捕获的正则表达式需要能过验证通过捕获对象字符串的 // 用同一个正则先去验证字符串的话, 这样捕获会出现问题, 此时可以在用同一个正则规则去验证, 不要使用同一个正则对象 if (reg.test(str)) { console.log(reg.lastIndex); // => 12 console.log(reg.exec(str)); // => ["412456", index: 18, input: "sdfsadf12354asdfas412456aasdf", groups: undefined] }
2.3 String.prototype.match方法: 捕获所有匹配组
这是字符串原型上的方法, 捕获所有匹配项
// 没有加修饰符g的时候, 直接返回第一匹配项
let reg = /\d+/;
let str = 'asf123asd124adf154adf';
str.match(reg) // => ["123", index: 3, input: "asf123asd124adf154adf", groups: undefined]
// ======================
// 返回所有匹配项
let reg = /\d+/g;
let str = 'asf123asd124adf154adf';
str.match(reg) // => ["123", "124", "154"]
// =======================
// 没有匹配项时, 返回null
let reg = /\d+/g;
let str = 'dfasdfsd';
str.match(reg) // => null
2.4 String.prototype.replace: 字符串替换方法
-
一般伴随正则一起使用 -- 正则可以全局替换
// 将suiyue替换成岁月 let str = 'suiyue@2019|suiyue@2020'; /* * 不使用正则 => str.replace('suiyue', '岁月') => 一次只能替换一个 * 使用正则 => str.replace(/suiyue/g, '岁月') */ // ====================== // 例子: 处理时间字符串 let time = '2019-08-13'; // => 处理为2019年08月13日 let reg = /^(\d{4})-(\d{1,2})-(\d${1,2})$/; // 实现方法一: $1为分组捕获的第一个, $2为分组捕获的第二个... time.replace(reg, '$1年$2月$3日'); // 实现方法二: time.replace(reg, (big, ...arg) => { // arg为剩余参数, 值为: $1-$9 // $1为分组捕获的第一个, $2为分组捕获的第二个... }) // ================ // 例子: 单词首字母大写 let str = 'good good study. day day asdf'; let reg = /\b([a-zA-Z])[a-zA-Z]*\b/g; // 函数被执行了六次(相当于执行一次捕获一个), 每一次都把正则匹配信息传递给函数 // => 每一次参数: ['good', 'g'] ['good', 'g'] ['study', 's']... str = str.replace(reg, (...arg) => { let [content, $1] = arg; $1 = $1.toUpperCase(); conetnt = content.substring(1); return $1 + content; }) console.log(str); // => Ggood Ggood Sstudy. Dday Dday Aasdf
3. 正则的分组捕获
-
一次匹配下, 分组捕获
let str = '360145199011220112';
/*
小括号作用;
1. 改变优先级
2. 分组捕获 => 会将捕获的内容进行分组捕获
*/
let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|x|X)/
* 多次匹配下, match只能把大正则匹配的内容获取到, 小分组(小括号分组)匹配的信息无法获取
```javascript
let str = '{0}年{1}月{2}日';
let reg = /\{(\d+)\}/g;
// 使用match分组捕获时, 多次匹配无法捕获组
console.log(str.match(reg)); // => ["{0}", "{1}", "{2}"]
-
分组的另一个作用: '分组引用'
let str = 'book'; // 假设需要保证中间两个字母相同 let reg = /^[a-zA-Z([a-zA-Z])\1[a-zA-Z]]$/; // => 分组引用就是通过'\数字'让其代表和对应分组出现一模一样的内容 console.log(reg.test('book)); // => true console.log(reg.test('deep)); // => true console.log(reg.test('some)); // => false
4. 正则捕获的贪婪性
-
默认情况下, 正则捕获的时候, 是按照当前正则所匹配的最长结果来获取的
let str = 'sdf230asdf123'; let reg = /\d+/g; // 2 和 3 和 0 ..应该都符合正则reg的, 但是因为正则捕获的贪婪性, 会按照最长结果来匹配 console.log(str.match(reg)); // => ['230', '123']; // ===================== // 在 量词元字符 后面设置? : 取消捕获时候的贪婪性(按照正则匹配的最短结果来获取) reg = /\d+?/g; console.log(str.match(reg)) // => ["2", "3", "0", "1", "2", "3"]
-
问号(?)在正则中的作用:
- 问号左边是非量词元字符: 本身代表量词元字符, 出现零到一次
- 问号左边是量词元字符: 取消捕获时候的贪婪性
- (?:) 只匹配不捕获
- (?=) 正向预查
- (?!)负向预查