如何按正则匹配拆分含占位符的字符串为数组并处理嵌套数组,有无模板库
实现思路
核心是放弃字符串拼接替换逻辑,改为按正则匹配位置拆分原字符串,再将匹配项映射为目标值插入拆分后的片段,同时配合递归处理嵌套数组。
具体实现
1. 单个字符串拆分工具函数
先实现处理单个字符串的逻辑,按匹配项位置切分,自动过滤空文本段:
/** * 按指定正则拆分字符串,匹配项映射为自定义值 * @param {string} str 待处理原字符串 * @param {RegExp} matchReg 全局匹配规则(需带g修饰符) * @param {(matchStr: string, matchInner: string) => any} mapMatchFn 匹配项映射函数,返回对应数组元素 * @returns {any[]} 拆分后的数组 */ function splitStrByMatch(str, matchReg, mapMatchFn) { const segments = []; let lastCursor = 0; // 遍历所有匹配项 for (const match of str.matchAll(matchReg)) { const matchStart = match.index; const matchEnd = matchStart + match[0].length; // 提取当前匹配前的非匹配文本,过滤空值 const beforeText = str.slice(lastCursor, matchStart).trim(); if (beforeText) segments.push(beforeText); // 插入匹配项的映射结果 segments.push(mapMatchFn(match[0], match[1])); // 更新游标到匹配项末尾 lastCursor = matchEnd; } // 处理最后一个匹配后的剩余文本 const afterText = str.slice(lastCursor).trim(); if (afterText) segments.push(afterText); return segments; }
效果验证
用给出的示例测试:
const testStr = 'stufff sjktasjtjser ((matchthis))'; // 匹配双括号规则,匹配项统一映射为'whatwhat' const result = splitStrByMatch(testStr, /\(\((.*?)\)\)/g, () => 'whatwhat'); console.log(result); // 输出 ['stufff sjktasjtjser', 'whatwhat'],符合预期
若字符串无匹配项,会直接返回包含原字符串的单元素数组;若字符串为纯匹配内容,会直接返回映射后的目标值数组,不会出现空数组。
2. 嵌套数组递归处理
通过递归遍历嵌套数组的每一项,字符串类型元素执行上述拆分逻辑,数组类型元素递归处理,其他类型(如原有对象)直接保留:
/** * 递归处理嵌套数组的字符串元素 * @param {any[]} arr 待处理嵌套数组 * @param {RegExp} matchReg 全局匹配规则 * @param {Function} mapMatchFn 匹配项映射函数 * @param {boolean} flatten 是否将拆分后的数组展开到上层(默认false) * @returns {any[]} 处理后的新数组 */ function processNestedArr(arr, matchReg, mapMatchFn, flatten = false) { const handler = flatten ? Array.prototype.flatMap : Array.prototype.map; return handler.call(arr, item => { if (Array.isArray(item)) { return processNestedArr(item, matchReg, mapMatchFn, flatten); } if (typeof item === 'string' && item) { return splitStrByMatch(item, matchReg, mapMatchFn); } return item; }); }
嵌套数组效果验证
const nestedTestArr = ['stufff', ['more stuff ((matchhere))'], '((andanother))']; // 默认不展开,保留原数组层级 const processedDefault = processNestedArr(nestedTestArr, /\(\((.*?)\)\)/g, () => 'whatwhat'); /* 输出: [ ['stufff'], [['more stuff', 'whatwhat']], ['whatwhat'] ] */ // 开启展开,拆分后的数组直接合并到上层 const processedFlatten = processNestedArr(nestedTestArr, /\(\((.*?)\)\)/g, () => 'whatwhat', true); /* 输出: ['stufff', 'more stuff', 'whatwhat', 'whatwhat'] */
灵活适配自定义输出需求
如果需要输出对象数组而非纯字符串,只需修改传入的mapMatchFn即可:
// 示例:将匹配项映射为指定结构的对象 const mapToObj = (matchStr, matchInnerContent) => ({ type: 'replaceNode', originText: matchInnerContent, target: 'whatwhat' }); const processedWithObj = processNestedArr(nestedTestArr, /\(\((.*?)\)\)/g, mapToObj); // 输出的数组中匹配项将直接为对应对象结构,无需额外转换
关于第三方库
不需要专门的模板库,上述逻辑完全可以自主实现。如果希望简化递归遍历的代码,可以使用通用工具库(如Lodash)提供的递归节点遍历方法,核心逻辑和上述实现一致,灵活性更高。
内容的提问来源于stack exchange,提问作者Ricardo Silva
相关产品推荐
相关产品推荐

