如何用JavaScript将含AND/OR逻辑的纯文本转为嵌套JSON对象并优化性能
如何用JavaScript将含AND/OR逻辑的纯文本转为嵌套JSON对象并优化性能
兄弟,我来帮你搞定这个问题!你的现有代码已经有了基础思路,但核心问题是没处理括号的层级关系,也没构建出带AND/OR键的嵌套结构,咱们一步步来调整,同时兼顾性能优化~
一、先搞定核心需求:构建正确的嵌套结构
首先,咱们得明确原字符串的逻辑:顶级是多个用AND连接的项,每个项要么是单个数字(被{}包裹),要么是括号包裹的、用OR连接的数字组。直接用split('AND')会有问题——如果括号里有AND(虽然你例子里没有,但得考虑通用情况),会错误分割括号内的内容。
所以第一步要写一个能忽略括号内内容的顶级运算符分割函数,然后再处理每个项:
function parseCondition(str) { // 先一次性去掉所有空格,减少后续处理麻烦 const cleanStr = str.replace(/\s+/g, ''); // 辅助函数:分割顶级运算符,括号内的内容不参与分割 function splitTopLevel(s, operator) { const result = []; let current = ''; let bracketDepth = 0; const opLength = operator.length; for (let i = 0; i < s.length; i++) { const char = s[i]; // 记录括号深度 if (char === '(' || char === '{') bracketDepth++; if (char === ')' || char === '}') bracketDepth--; // 只有当括号深度为0时,才匹配顶级运算符 if (bracketDepth === 0 && s.slice(i, i + opLength) === operator) { result.push(current); current = ''; i += opLength - 1; // 跳过运算符的剩余字符 } else { current += char; } } result.push(current); return result; } // 分割顶级的AND项 const andItems = splitTopLevel(cleanStr, 'AND'); // 处理每个AND项,生成对应结构 const parsedAnd = andItems.map(item => { // 去掉项外层的括号/大括号(比如{2109}或(xxx)) const content = item.replace(/^[\{\(](.*)[\}\)]$/, '$1'); // 如果内容包含OR,说明是OR组,构建{or: [...]}对象 if (content.includes('OR')) { const orItems = splitTopLevel(content, 'OR'); // 把每个OR项转成数字(去掉可能的{}) const numbers = orItems.map(numStr => Number(numStr.replace(/[\{\}]/g, ''))); return { or: numbers }; } else { // 单个数字,直接转成数值 return Number(content.replace(/[\{\}]/g, '')); } }); // 最终返回顶级的AND结构 return { and: parsedAnd }; } // 测试你的例子 const optionString = '{2109} AND ({2370} OR {1701} OR {2702}) AND {1234} AND ({2245} OR {2339})'; console.log(parseCondition(optionString));
运行后就能得到你想要的结构:
{ and: [ 2109, { or: [2370, 1701, 2702] }, 1234, { or: [2245, 2339] } ] }
二、性能优化方案
如果要处理非常长的条件字符串,咱们可以优化几点,提升运行效率:
1. 减少正则表达式的使用
正则虽然方便,但多次调用会有性能开销,咱们可以用遍历的方式提取数字,代替正则替换:
// 替换原来的数字转换逻辑,用这个辅助函数 function extractNumber(str) { let numStr = ''; for (const char of str) { // 匹配数字和负号(支持负数场景) if (!isNaN(char) || char === '-') { numStr += char; } } return Number(numStr); }
2. 提前预处理,避免重复操作
比如一次性去掉所有空格,而不是每次处理项的时候再trim或替换;缓存运算符的长度,避免循环中重复计算。
3. 直接处理括号,不用正则替换
判断项是否被括号包裹时,直接用字符串的startsWith和endsWith,比正则更快:
// 替换原来的content提取逻辑 let content = item; if ((content.startsWith('(') && content.endsWith(')')) || (content.startsWith('{') && content.endsWith('}'))) { content = content.slice(1, -1); }
整合后的优化版代码:
function parseConditionOptimized(str) { // 一次性去掉所有空格 const cleanStr = str.replace(/\s+/g, ''); // 辅助函数:分割顶级运算符 const splitTopLevel = (s, op) => { const res = []; let current = ''; let depth = 0; const opLen = op.length; for (let i = 0; i < s.length; i++) { const c = s[i]; if (c === '(' || c === '{') depth++; if (c === ')' || c === '}') depth--; if (depth === 0 && s.slice(i, i + opLen) === op) { res.push(current); current = ''; i += opLen - 1; } else { current += c; } } res.push(current); return res; }; // 辅助函数:提取字符串中的数字 const extractNumber = s => { let numStr = ''; for (const c of s) { if (!isNaN(c) || c === '-') numStr += c; } return Number(numStr); }; const andItems = splitTopLevel(cleanStr, 'AND'); const parsedAnd = andItems.map(item => { // 去掉外层括号/大括号 let content = item; if ((content.startsWith('(') && content.endsWith(')')) || (content.startsWith('{') && content.endsWith('}'))) { content = content.slice(1, -1); } if (content.includes('OR')) { const orItems = splitTopLevel(content, 'OR'); return { or: orItems.map(extractNumber) }; } else { return extractNumber(content); } }); return { and: parsedAnd }; }
三、为什么你的原有代码不行?
你的代码直接用split('AND')分割,会把括号内的内容也错误分割(如果括号里有AND的话);而且只是把结果转成了二维数组,没有根据OR的存在构建对应的{or: [...]}对象,也没有顶级的and键。用上面的方法就能完美解决这些问题啦~
备注:内容来源于stack exchange,提问作者ha kuna
相关产品推荐
相关产品推荐

