JS 匹配接口返回结果差异
几个匹配接口的返回结构完全不同,混用是 JS 正则最常见的困惑来源:字符串的匹配方法在没有全局标志时返回带分组的对象,有全局标志时只返回整体匹配的字符串数组而丢掉分组;正则对象的执行方法始终返回带分组的对象,但启用全局或粘性标志后带状态;还有一个专门返回迭代器的接口,兼顾分组与遍历。
基本信息
| 字符串匹配方法 | 无全局标志时返回首个匹配的详细信息,有全局标志时返回所有整体匹配的字符串数组 |
|---|---|
| 正则执行方法 | 返回首个匹配的详细信息,含分组与位置;全局或粘性标志下推进状态 |
| 迭代接口 | 要求全局标志,返回迭代器,每项都是详细匹配结果,可安全遍历 |
| 其他接口 | 搜索返回首个匹配位置,测试返回布尔值,切分按模式拆分字符串 |
典型使用场景
- 需要分组取值:用执行方法或迭代接口,字符串匹配方法在全局模式下拿不到分组
- 批量遍历全部匹配:用迭代接口最省心,无需手动管理状态
- 仅判断是否存在:用测试接口,注意启用全局或粘性标志后会带状态
- 定位首次出现位置:用搜索接口,返回值是下标而非匹配内容
- 按分隔符拆分并保留分隔符:切分接口在模式含捕获组时会把分隔符也放进结果
返回结构差异实测
返回结构差异实测
const s = 'a-1 b-2';
s.match(/(?<w>\w+)-(\d+)/g); // ['a-1', 'b-2']:全局模式下没有分组信息
s.match(/(?<w>\w+)-(\d+)/); // 返回对象:含 groups、index、input
[...s.matchAll(/(?<w>\w+)-(\d+)/g)] // 迭代器,每项含分组与 groups
.map(m => m.groups.w); // ['a', 'b']:兼顾分组与批量遍历
/a/g.exec('aa'); // 全局对象带状态,两次调用位置不同
s.search(/\d/); // 返回首个数字的下标
/a/.test('a'); // 返回布尔值
'a1b'.split(/(\d)/); // ['a', '1', 'b']:捕获组会保留分隔符接口返回对照
| 接口 | 返回内容 | 是否含分组 |
|---|---|---|
| 字符串匹配,无全局标志 | 匹配详情对象 | 含 |
| 字符串匹配,有全局标志 | 整体匹配字符串数组 | 不含 |
| 正则执行方法 | 匹配详情对象 | 含 |
| 迭代接口 | 匹配详情迭代器 | 含 |
| 搜索 | 下标数字 | 不含 |
| 测试 | 布尔值 | 不含 |
迭代接口要求正则带全局标志,否则会抛类型错误;它内部会基于原正则创建用于遍历的副本,因此原对象的当前位置仍会影响遍历起点,共享正则对象前最好先确认状态。
用执行方法循环遍历时必须在结果为 null 时退出:匹配失败会把状态复位,若循环条件写得不对,很容易出现反复从起点开始或直接死循环。