JavaScript中如何获取正则表达式重复分组的所有匹配结果?
SVG路径表达式解析:正则匹配重复分组的解决方案
我需要解析SVG <path> 元素中的路径表达式,方便在JavaScript里对点做变换。一开始尝试用正则表达式解析(代码如下),但结果不符合预期——只能捕获每个重复分组的最后一次出现。想知道怎么实现预期效果?能不能只用正则表达式完成?如果JS正则只能这样,我会考虑先用正则初步匹配,再用常规JS完成剩余解析,但先想了解有没有其他基于正则的方案,同时也想更好掌握正则的用法。
let path = `M4,24 L4,23 Q12,23,12, 9 L14, 9 C15, 3,25, 3,26,9 L28,9 Q28,23,36,23 L36,24 Z` // 此函数无法正常工作 function parsePath(path) { // 为简化正则匹配,先处理路径字符串: // 将所有逗号和空白字符替换为单个空格分隔符 let path2 = path.replaceAll(/[,\s]+/g, ' ') let rgx = /([A-Za-z])(?:(\d+)\s+)*/g let matches = [...path2.matchAll(rgx)].map(x => { return [x[1], x.slice(2)] }) return matches } console.log(parsePath(path)); // 实际输出: [ [ 'M', [ '24' ] ], [ 'L', [ '23' ] ], [ 'Q', [ '9' ] ], [ 'L', [ '9' ] ], [ 'C', [ '9' ] ], [ 'L', [ '9' ] ], [ 'Q', [ '23' ] ], [ 'L', [ '24' ] ], [ 'Z', [ undefined ] ] ] // 预期输出: [ [ 'M', [ '4', '24' ] ], [ 'L', [ '4', '23' ] ], [ 'Q', [ '12', '23', '12', '9' ] ], // ... ]
问题原因
JavaScript正则中的重复捕获组只会保留最后一次匹配的结果,之前的匹配内容会被覆盖。你写的正则(?:(\d+)\s+)*里,(\d+)每次匹配数字都会更新捕获组的内容,最终只留下最后一个数字,这就是为什么实际输出里每个命令只拿到最后一个数值。
解决方案
由于JS正则本身不支持直接捕获重复分组的所有匹配结果,更实用的方式是分两步处理:
方案:拆分命令+提取数字
- 先把路径字符串标准化,统一用空格分隔所有元素
- 用正则匹配每个命令(字母)和对应的所有数字片段
- 把每个数字片段拆分成单独的数值数组
修改后的代码如下:
function parsePath(path) { // 标准化路径:逗号/空白替换为单个空格,去除首尾空格 const normalizedPath = path.replace(/[,\s]+/g, ' ').trim(); // 匹配每个命令:字母 + 后续所有数字(空格分隔) const commandRegex = /([A-Za-z])([\d\s]*)/g; const result = []; let match; while ((match = commandRegex.exec(normalizedPath)) !== null) { const [, command, numStr] = match; // 拆分数字串,过滤空值(避免首尾空格导致的空元素) const numbers = numStr.trim().split(/\s+/).filter(Boolean); result.push([command, numbers]); } return result; } // 测试输出 console.log(parsePath(path));
执行后会得到符合预期的结果:
[ [ 'M', [ '4', '24' ] ], [ 'L', [ '4', '23' ] ], [ 'Q', [ '12', '23', '12', '9' ] ], [ 'L', [ '14', '9' ] ], [ 'C', [ '15', '3', '25', '3', '26', '9' ] ], [ 'L', [ '28', '9' ] ], [ 'Q', [ '28', '23', '36', '23' ] ], [ 'L', [ '36', '24' ] ], [ 'Z', [] ] ]
补充说明
如果想针对不同SVG命令的数字数量(比如M/L需要2个数字,Q需要4个,C需要6个)做更严格的校验,可以在拆分数字后根据命令类型做处理,但上面的方案已经能满足基础的解析需求。
内容的提问来源于stack exchange,提问作者PizzaOverflow
相关产品推荐
相关产品推荐

