进阶型元字符
| 元字符 | 中文名称 | 匹配对象 |
|---|---|---|
(char) | 捕获型括号 | 限定多选结构、分组、捕获结果 |
(?:char) | 非捕获型括号 | 匹配char,但不捕获该结果 |
(?>char) | 固化分组(暂不支持) | 匹配char,且不交还还分组里的任何字符 |
(?<name>) | 命名捕获 | 命名捕获分组内容,并通过name调用捕获内容 |
注意
char为要匹配的字符串或表达式;name为合法的JavaScript标识符,描述了捕获的内容;- 固化分组
(?>char)至今不被JavaScript支持。
语法声明
本页示例均使用的JavaScript正则语法声明 const regexp = /pattern/flags:
捕获型括号 ()
多层捕获括号嵌套时的捕获顺序:
- 若左侧的捕获括号内无嵌套捕获括号,则按表达式中出现的顺序
从左到右依次捕获; - 若左侧的捕获括号内有嵌套捕获括号,则先在该处按
从外到内的顺序依次捕获,再按表达式中出现的顺序从左到右依次捕获; - 若在从左到右的捕获中出现了上面 2 中的情况,依然按照 2 中的方法处理; 出现 1 中的情况,则按 1 中的方法处理。
为了更好的理解捕获顺序,举个简单的例子:
javascript
const str = "Design by AchooLuv";
const regexp = /(ac(hoo))(luv)/i; // 捕获分组顺序:['Achoo', 'hoo', 'Luv']
const result = str.match(regexp);
console.log(result); // 匹配结果为: AchooLuv从匹配结果发现,捕获的顺序依次是:['Achoo', 'hoo', 'Luv'],符合前面表述的:从外到内,从左到右。
表达式内的反向引用
在正则表达式内部我们可以使用反向引用捕获分组内容,其格式: \n
注意
n为数字,从1开始计数,表示第n个捕获分组。
javascript
const str = "Design by AchooLuvAchooLuvAchooLuv";
const regexp = /(achoo)(luv)\1/i; // 捕获分组顺序:['Achoo', 'Luv']
const result = str.match(regexp);
console.log(result); // 匹配结果为: AchooLuvAchoo在正则表达式中我们通过\1引用了捕获分组内容(achoo),所以此时的匹配结果为'AchooLuvAchoo'。
反向引用被捕获后也可被引用
javascript
const str = "Design by AchooLuvAchooLuvAchooLuv";
const regexp = /(achoo)(luv)(\1)(\2)\3/i; // 捕获分组顺序:['Achoo', 'Luv', 'Achoo', 'Luv']
const result = str.match(regexp);
console.log(result); // 匹配结果为: AchooLuvAchooLuvAchoo我们使用\1引用表达式中的(achoo),并将\1捕获,然后使用\3引用表达式中的(\1)。
通过$1~$9直接引用捕获内容
比如我们视图将AchooLuv改成LuvAchoo:
javascript
const str = "Design by AchooLuv";
const result = str.replace(/(achoo)(luv)/i, "$2$1");
console.log(result); // 匹配结果为: Design by LuvAchoo
// 也可以通过全局对象RegExp来引用
console.log(RegExp.$1, RegExp.$2); // 依次输出:Achoo Luv非捕获型括号 (?:)
顾名思义,非捕获型括号只匹配内容,不会捕获内容,所以也无法引用其匹配的内容。
javascript
const str = "Design by AchooLuv";
const regexp = /(?:achoo)(luv)/i;
const result = str.match(regexp);
console.log(RegExp.$1); // 输出结果为: Luv固化分组 (?>)
很遗憾
JavaScript至今不支持固化分组功能!!!
命名捕获 (?<>)
注意
命名捕获是ES9才正式支持的正则新特性,使用时需要注意浏览器支持情况!!!
假设我们想在一字符串中提取按YYYY-MM-DD格式表示的时间,并拿到对应的 年 月 日 ,像这样(此处简化了字符串):
javascript
const regexp = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/;
const {
groups: { day, month, year },
} = regexp.exec("1995-05-26"); // 解构赋值
console.log(year, month, day); // 输出结果:1995 05 26可以看见我们的命名捕获生效了,在解构赋值时,命名的变量都取到了对应的值。
