JavaScript多行命名捕获正则在regex101正常但单次exec不全匹配
一次性捕获多行字符串中所有命名正则组的解决方案
我需要用JavaScript正则从多行字符串中捕获构建信息,原正则在regex101中能看到完整的捕获结果,但单次调用exec只能拿到第一个匹配项,其余命名组都是undefined。
原正则:
/(BuildTimestamp:)(?<timestamp>.*)|(VersionCode:)(?<major>.*)|(VersionName:)(?<minor>.*)/gm
测试字符串:
BuildTimestamp:30-May-2023 14:25 VersionCode:6 VersionName:.0.5
原代码:
const regex = /(BuildTimestamp:)(?<timestamp>.*)|(VersionCode:)(?<major>.*)|(VersionName:)(?<minor>.*)/gm; const match = regex.exec(contents);
问题原因
问题出在正则结构和JavaScript的exec行为上:
- 原正则用
|分支,每个分支对应一个命名组,全局模式下exec每次调用仅返回一个分支的匹配结果,所以单次调用只能拿到第一个匹配行的命名组,其余组自然是undefined。 - regex101展示的是多次匹配结果的汇总,并非单次匹配的结果,所以看起来能一次性拿到所有组。
解决方案
方案1:使用matchAll整合所有匹配结果
matchAll会返回所有全局匹配结果的迭代器,通过遍历迭代器可以把所有命名组合并到一个对象中:
const contents = `BuildTimestamp:30-May-2023 14:25 VersionCode:6 VersionName:.0.5`; const regex = /(BuildTimestamp:)(?<timestamp>.*)|(VersionCode:)(?<major>.*)|(VersionName:)(?<minor>.*)/gm; const matches = [...contents.matchAll(regex)]; const buildInfo = matches.reduce((acc, currentMatch) => { return {...acc, ...currentMatch.groups}; }, {}); console.log(buildInfo); // 输出:{ timestamp: '30-May-2023 14:25', major: '6', minor: '.0.5' }
这个方案的优点是灵活,即使行的顺序变化、存在额外行,也能正确提取目标信息。
方案2:修改正则匹配整个字符串,一次性捕获所有组
如果构建信息的行顺序和格式固定,可以直接写一个匹配整个字符串的正则,一次性捕获所有命名组:
const contents = `BuildTimestamp:30-May-2023 14:25 VersionCode:6 VersionName:.0.5`; const regex = /BuildTimestamp:(?<timestamp>.*)\nVersionCode:(?<major>.*)\nVersionName:(?<minor>.*)\n?/; const match = regex.exec(contents); if (match) { console.log(match.groups); // 输出:{ timestamp: '30-May-2023 14:25', major: '6', minor: '.0.5' } }
正则末尾的\n?是为了兼容字符串末尾可能存在的换行符。这个方案性能更高,但依赖固定的行顺序和格式。
内容的提问来源于stack exchange,提问作者Clint Singer
相关产品推荐
相关产品推荐

