js中正则表达式中【exec】用法深度解读

exec() 是 JavaScript 正则表达式对象(RegExp)中的一个方法,用于匹配字符串中的特定模式,并返回匹配结果。它比 test()match() 更强大,因为它不仅仅返回匹配成功与否,还返回匹配的具体内容及其相关信息。下面详细讲解 exec() 的相关知识点。

1. 基本语法

javascript 复制代码
let regex = /模式/;
let result = regex.exec(字符串);

exec() 方法接受一个字符串作为参数,并返回一个数组,该数组表示匹配的结果。如果没有找到匹配,则返回 null

2. 返回值解释

exec() 找到匹配时,它返回一个数组,其中包含:

  • [0]:匹配到的整个字符串。
  • [1] 及其他:捕获组的内容(如果正则表达式使用了捕获组,如 ())。
  • index:匹配的开始位置(在原字符串中的起始索引)。
  • input:被搜索的原字符串。
  • groups:一个对象,包含所有命名捕获组的匹配内容(如果有使用命名捕获组)。
例子:
javascript 复制代码
let regex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
let result = regex.exec("2023-09-24");
console.log(result);

输出结果:

javascript 复制代码
[
  '2023-09-24',   // 匹配到的整个字符串
  '2023',         // 第一个捕获组:年份
  '09',           // 第二个捕获组:月份
  '24',           // 第三个捕获组:日期
  index: 0,       // 匹配的起始索引
  input: '2023-09-24',  // 被搜索的字符串
  groups: {       // 命名捕获组
    year: '2023',
    month: '09',
    day: '24'
  }
]

在这个例子中,使用了命名捕获组(通过 (?<name>pattern) 语法),并且 exec() 的返回结果中 groups 属性包含了命名捕获组的匹配结果。

3. 捕获组 (Capturing Groups)

捕获组用 () 括起来,它可以匹配并提取部分字符串。你可以通过使用 exec() 来获取这些捕获的内容。命名捕获组可以为每个捕获的部分命名,方便后续使用。

捕获组例子:
javascript 复制代码
let regex = /(\d+)\s(\w+)/;  // 匹配:数字 空格 字母组合
let result = regex.exec("123 abc");
console.log(result);

输出:

javascript 复制代码
[
  '123 abc',  // 整个匹配的字符串
  '123',      // 捕获组 1:数字部分
  'abc',      // 捕获组 2:字母部分
  index: 0,   // 匹配开始的索引
  input: '123 abc'
]
命名捕获组例子:
javascript 复制代码
let regex = /(?<number>\d+)\s(?<word>\w+)/;
let result = regex.exec("123 abc");
console.log(result.groups);

输出:

javascript 复制代码
{
  number: '123',  // 捕获组 1:命名为 number
  word: 'abc'     // 捕获组 2:命名为 word
}

4. 全局标志 (Global Flag)

如果你在正则表达式中使用了全局标志(g),exec() 会在每次调用时继续从上次匹配结束的位置开始匹配。你需要多次调用 exec() 才能找到所有匹配。

示例:
javascript 复制代码
let regex = /\d+/g;
let str = "123 456 789";
let result;

while ((result = regex.exec(str)) !== null) {
  console.log(result);
}

输出:

javascript 复制代码
[ '123', index: 0, input: '123 456 789' ]
[ '456', index: 4, input: '123 456 789' ]
[ '789', index: 8, input: '123 456 789' ]

每次调用 exec(),它会返回下一个匹配的结果,直到返回 null,表示没有更多匹配。

5. lastIndex 属性

在全局匹配模式下,正则表达式对象的 lastIndex 属性会记录下次匹配开始的位置。每次匹配后,lastIndex 会更新,帮助 exec() 从上次结束的位置继续匹配。

示例:
javascript 复制代码
let regex = /\d+/g;
let str = "123 456 789";
let result = regex.exec(str);

console.log(result);  // 匹配 123
console.log(regex.lastIndex);  // 输出 3

result = regex.exec(str);
console.log(result);  // 匹配 456
console.log(regex.lastIndex);  // 输出 7

6. 命名捕获组的优势

命名捕获组(使用 (?<name>pattern) 语法)可以让匹配结果更具可读性,特别是当你需要提取多个不同的部分时。

示例:
javascript 复制代码
let regex = /(?<areaCode>\d{3})-(?<prefix>\d{3})-(?<lineNumber>\d{4})/;
let result = regex.exec("555-123-4567");
console.log(result.groups);

输出:

javascript 复制代码
{
  areaCode: '555',
  prefix: '123',
  lineNumber: '4567'
}

通过 groups 属性,你可以更方便地获取并使用这些命名捕获的结果,而不需要依赖捕获组的顺序。

7. exec() 和其他方法的比较

  • test():返回布尔值,表示正则表达式是否匹配字符串。
  • match() :如果是非全局正则表达式,它与 exec() 类似,但全局正则时,它一次性返回所有匹配项。
  • exec():可以返回详细的匹配结果,包括捕获组和匹配位置。
示例:
javascript 复制代码
let regex = /\d+/g;
let str = "123 456 789";

// 使用 exec() 逐步匹配
let result;
while ((result = regex.exec(str)) !== null) {
  console.log(result[0]);  // 依次输出 123, 456, 789
}

// 使用 match() 一次性匹配
let matches = str.match(regex);
console.log(matches);  // ['123', '456', '789']

8. 常见错误

  • 忘记考虑全局标志和lastIndex :当使用全局正则时,exec() 会记住上次匹配结束的位置。如果不注意,可能导致跳过某些匹配。
  • 忽略捕获组:如果想提取特定内容但没有使用捕获组,匹配结果中就不会包含这些信息。
  • 没有处理命名捕获组 :如果正则中使用了命名捕获组,但未正确访问 groups 属性,就无法获取命名捕获结果。

9. 总结

  • exec() 是非常灵活的正则表达式方法,适用于需要提取复杂匹配结果的场景。
  • 它不仅能返回匹配结果,还能提供匹配的索引和原字符串,且在全局模式下可以通过 lastIndex 实现连续匹配。
  • groups 属性为命名捕获组提供了直观的方式来访问匹配结果,使正则表达式的应用更加便捷。
相关推荐
小菜yh8 分钟前
后端人需知
java·前端·javascript·vue.js·设计模式
周万宁.FoBJ11 分钟前
vue3 实现文本内容超过N行折叠并显示“...展开”组件
开发语言·前端·javascript
w2sfot13 分钟前
JS加密=JS混淆?(JS加密、JS混淆,是一回事吗?)
javascript·js加密·js混淆
stormsha19 分钟前
Java中使用接口实现回调函数的详解与示例
java·开发语言·python
是小恐龙啊20 分钟前
单链表的增删改查(数据结构)
c语言·开发语言·数据结构·算法
鸽芷咕26 分钟前
【C++报错已解决】std::ios_base::sync_with_stdio
开发语言·c++·ios·bug
Jiaberrr31 分钟前
uniapp视频禁止用户推拽进度条并保留进度条显示的解决方法——方案二
前端·javascript·uni-app·音视频
python资深爱好者34 分钟前
VB中如何实现设计模式(如单例模式、工厂模式等)
javascript·单例模式·设计模式
korgs1 小时前
dea插件开发-自定义语言9-Rename Refactoring
java·开发语言
人工智能的苟富贵1 小时前
全面解析 iOS 和 Android 内嵌 H5 页面通信与交互实现方案
android·javascript·ios·交互