js字符串怎么用match转数组/.exec

作者:代码拾荒时间:2026-11-13 12:46:02浏览:447

深入讲解 JavaScript 中如何利用 String.prototype.match() 与 RegExp.prototype.exec() 将字符串提取转换为数组。系统解析全局修饰符 g、括号捕获组、lastIndex 游标推进机制以及现代 matchAll 的最佳实践。

在 JavaScript 中将字符串按特定模式拆解并提取为数组,核心取决于两件事:是否需要提取所有出现的子串,以及是否需要保留正则表达式圆括号中的“捕获组”。若只需获取全部满足规则的文本片段,使用带有全局修饰符 /g 的 str.match(regexp) 可以直接输出目标一维数组;若需要提取每一处匹配中的局部细节(捕获组),则应使用 regexp.exec(str) 配合 while 循环逐次推进游标装配数组,或在现代环境中使用 Array.from(str.matchAll(regexp)) 进行一步转换。
js字符串怎么用match转数组/.exec
缩略图:JavaScript 字符串利用 match 与 exec 转化为数组的两种核心处理路径

一、使用 match() 方法将字符串转为数组

String.prototype.match() 是字符串实例上的原生检索方法。调用 str.match(regexp) 时,返回值的形态与正则表达式是否声明了全局标志 g 存在直接绑定关系。掌握这种分流机制,是正确获取数组的第一步。

1. 全局匹配模式:直接提取所有匹配项为一维数组

当正则表达式末尾附加 g 修饰符时,match() 会扫描整个字符串,将所有符合规则的子串依次提取并放入一个新数组中返回。

const rawText = "订单号: SO202401, 金额: 199元; 订单号: SO202402, 金额: 350元";

// 提取所有连续订单号(以 SO 开头后接数字)
const orderNumbers = rawText.match(/SO\d+/g);

console.log(orderNumbers);
console.log(Array.isArray(orderNumbers));
示例输出:
[ 'SO202401', 'SO202402' ]
true

此时返回的 orderNumbers 是纯正的 JavaScript 数组,可以直接调用 map()、filter() 或通过 .length 获取匹配项总数。

注意防范 null 崩溃:若字符串中没有任何字符符合正则规则,match() 不会返回空数组 [],而是返回 null。若直接对结果调用数组方法(如 str.match(...).map(...)),会抛出 TypeError: Cannot read properties of null。在实际业务中应始终提供默认空数组回退:
const safeList = text.match(/\d+/g) || [];

2. 单次匹配模式:提取首个匹配项及内部捕获组

若正则没有加 g 标志,match() 只查找第一个匹配项。此时返回的虽然仍是一个类数组对象(Array.isArray() 返回 true),但其元素排列遵循特殊的结构:索引 0 为完整匹配子串,索引 1 到 n 对应正则中各个小括号 () 所声明的捕获组。

const logItem = "2026-11-10 [ERROR] Database timeout";
const matchResult = logItem.match(/(\d{4}-\d{2}-\d{2})\s+\[([A-Z]+)\]\s+(.*)/);

// 使用解构赋值直接转换为常规变量或数组
const [fullMatch, date, level, message] = matchResult || [];

console.log(matchResult);
console.log("日期:", date, "级别:", level);
示例输出:
[
  '2026-11-10 [ERROR] Database timeout',
  '2026-11-10',
  'ERROR',
  'Database timeout',
  index: 0,
  input: '2026-11-10 [ERROR] Database timeout',
  groups: undefined
]
日期: 2026-11-10 级别: ERROR
js字符串怎么用match转数组/.exec
图 1:String.prototype.match() 转数组决策流程与结构分流

二、match() 与 RegExp.prototype.exec() 的底层区别

在很多场景中,读者会发现 match() 和 exec() 可以得到类似的结果,但二者的调用主体、状态维护和返回机制有本质差别:

  • 调用方差异:str.match(reg) 是字符串方法,由字符串驱动;reg.exec(str) 是正则表达式实例的方法,由正则对象驱动。
  • 无 g 标志时完全等价:当不包含 /g 时,str.match(reg) 底层直接委托调用 reg.exec(str),返回包含捕获组及 index、input、groups 属性的同构数组。
  • 带 g 标志时行为分化:match(/.../g) 一次性遍历整个字符串,但抛弃所有捕获组;而 exec() 无论是否带 g,单次调用永远只返回一个匹配及其完整捕获组。
js字符串怎么用match转数组/.exec
图 2:match() [无/g] 与 RegExp.prototype.exec() 单次返回数组结构解剖

三、用 regexp.exec() 循环提取完整数组的标准步骤

当业务要求既要提取字符串中“所有出现的匹配项”,又要获取每一项里的“括号捕获组”时,match(/.../g) 无法完成任务。此时的经典解决方案是使用 regexp.exec(str) 配合 while 循环。

1. 游标 lastIndex 与 while 循环机制

当正则表达式设置了 g 修饰符时,正则实例对象内部会维护一个名为 lastIndex 的整数属性,记录下一次匹配扫描的起始索引。

  1. 第一次执行 reg.exec(str),从索引 0 开始匹配,找到后将 lastIndex 设为该匹配项末尾的下一个字符位置,并返回匹配详情数组。
  2. 第二次调用 reg.exec(str),自动从上一次停下的 lastIndex 位置继续向后搜索。
  3. 当找不到更多匹配时,exec() 返回 null,同时自动将 lastIndex 重置为 0。
js字符串怎么用match转数组/.exec
图 3:RegExp.prototype.exec() 在 while 循环中推进 lastIndex 转数组机制

2. 编写标准化提取代码

以下代码演示如何从一段样式文本中,提取所有的 CSS 键值对,组装成结构化对象数组:

const cssString = "color: #333; font-size: 14px; background: #fff;";

// 必须带上 g 标志,并用圆括号声明捕获组
const ruleRegex = /([a-z-]+)\s*:\s*([^;]+);/g;

// 准备接收结果的目标数组
const parsedRules = [];
let match;

// 赋值表达式放在条件判断中,直到返回 null 终止
while ((match = ruleRegex.exec(cssString)) !== null) {
  parsedRules.push({
    property: match[1].trim(),
    value: match[2].trim(),
    startIndex: match.index
  });
}

console.log(parsedRules);
示例输出:
[
  { property: 'color', value: '#333', startIndex: 0 },
  { property: 'font-size', value: '14px', startIndex: 13 },
  { property: 'background', value: '#fff', startIndex: 31 }
]
关键警示:避免无限死循环与状态残留
1. 遗漏 /g 标志:如果正则没有声明 g,ruleRegex.lastIndex 永远保持为 0,exec() 每次都命中第一个匹配,while 循环将陷入死循环,耗尽 CPU 导致页面或进程卡死。
2. 正则实例全局复用污染:若将带 /g 的正则对象保存在全局或模块顶层变量中,并在多次解析中复用,一旦前一次匹配中途使用 break 退出,lastIndex 将停留在中间位置。下一次解析其他字符串时,会直接从该非零位置开始匹配,造成前面部分内容神秘丢失。在循环前手动将 ruleRegex.lastIndex = 0; 是一种良好的防御习惯。

四、现代最佳实践:ES2020 的 matchAll() 转数组

ECMAScript 2020 (ES11) 为字符串引入了 matchAll() 方法。它专门用于解决 match(/.../g) 丢失捕获组、以及 exec() 需手动维护 while 循环繁琐易错的问题。

str.matchAll(regexp) 返回一个迭代器对象,正则表达式必须包含 /g 标志(否则直接抛出 TypeError)。配合展开运算符 [...iter] 或 Array.from(),可以瞬间转换为包含每项匹配及其所有捕获组的二维数组。

const dataStr = "apple: $5.5, banana: $3.2, orange: $4.0";
const itemRegex = /([a-z]+):\s*\$([0-9.]+)/g;

// 方式 A:使用 Array.from 直接转为常规数组
const allMatches = Array.from(dataStr.matchAll(itemRegex));

// 方式 B:结合 map 进一步纯化提取捕获组
const pureList = allMatches.map(([full, fruit, price]) => ({
  fruit,
  price: Number(price)
}));

console.log(pureList);
示例输出:
[
  { fruit: 'apple', price: 5.5 },
  { fruit: 'banana', price: 3.2 },
  { fruit: 'orange', price: 4 }
]
js字符串怎么用match转数组/.exec
图 4:字符串正则转数组方案选型矩阵与核心维度对比

五、实战方案对比与选型建议

针对不同的业务开发需求,开发者可以根据下表迅速确定最简便、最安全的转换方式:

需求场景 推荐方案 代码写法示例 主要优势与注意
仅提取所有符合格式的文本片段 str.match(/.../g) str.match(/\d+/g) || [] 代码最短、可读性极高。注意使用 || [] 防止空指针。
提取单个目标及其各级捕获组 str.match(/.../)(无 g) const [all, p1] = str.match(/(a)(b)/) || [] 开箱即用,通过数组解构直接获取括号对应内容。
现代工程提取所有项及捕获组 Array.from(str.matchAll(/.../g)) [...str.matchAll(/(\w+)=(\w+)/g)] 无死循环风险,状态安全,现代浏览器与 Node.js 12+ 全面支持。
兼容老旧运行环境或大文本流式处理 reg.exec(str) 配合 while while ((m = reg.exec(str))) { ... } 完全兼容旧版 ES5 环境,可随时通过 break 中断,节约内存。
作者最新文章
相关文章
更多