You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript中基于带AND/OR的条件字符串筛选JSON数组

解决方案:JavaScript处理带逻辑运算符和嵌套括号的条件筛选

针对你的需求,这里提供两种可行的实现思路,分别适用于不同场景:

方法一:将条件字符串转换为JS表达式(简单快速)

核心思路是把你的条件字符串转换成合法的JavaScript逻辑表达式,通过函数执行来判断每个数据项是否符合条件。同时需要处理数据中键名大小写、空格不一致的问题。

实现代码

// 归一化对象键名:转小写+去除首尾空格
function normalizeObj(obj) {
  const normalized = {};
  Object.keys(obj).forEach(key => {
    const normalizedKey = key.trim().toLowerCase();
    normalized[normalizedKey] = obj[key];
  });
  return normalized;
}

// 将条件字符串转换为可执行的JS表达式
function convertCondition(conditionStr) {
  // 替换转义引号
  let expr = conditionStr.replace(/"/g, '"');
  // 替换 "Key": "Value" 为 normalizedObj['归一化Key'] === 'Value'
  expr = expr.replace(/"([^"]+)":\s*"([^"]+)"/g, (match, rawKey, value) => {
    const normalizedKey = rawKey.trim().toLowerCase();
    // 转义字符串中的单引号,避免语法错误
    const escapedValue = value.replace(/'/g, "\\'");
    return `normalizedObj['${normalizedKey}'] === '${escapedValue}'`;
  });
  // 替换逻辑运算符
  expr = expr.replace(/\bAND\b/g, '&&').replace(/\bOR\b/g, '||');
  return expr;
}

// 筛选函数
function filterData(data, conditionStr) {
  try {
    const conditionExpr = convertCondition(conditionStr);
    // 生成判断函数,避免重复编译
    const testFn = new Function('normalizedObj', `return ${conditionExpr};`);
    return data.filter(item => {
      const normalized = normalizeObj(item);
      return testFn(normalized);
    });
  } catch (err) {
    console.error('条件解析失败:', err);
    return [];
  }
}

// 测试示例
const Data = [
  {Application: 'APIM', Owner: 'Vande Mataram','Customer Code': 'DJLFKASJF',Environment: 'Dev',OS: 'Linux',Region: 'EU','TEAM ': 'DemoTestCOE'},
  {TEAM: 'BCC'},
  {Team: 'DemoTestCOE','Customer Code': 'DJLFKASJF',Owner: 'Vande Mataram',Environment: 'Prod',Region: 'EU',Application: 'Ui-Path',OS: 'Windows'},
  {Application: 'MGMT','Customer Code': 'DJLFKASJF', os: 'Windows','Owner ': 'Vande Mataram', Region: 'East US 2',Team: 'DemoTestCOE',Environment: 'MGMT'  },
  {Application: 'PIER',Owner: 'Govindarajulu Balaji',OS: 'Windows',Region: 'DemoTestCOE', Environment: 'QA'}  
];

const condition = '"Owner": "Vande Mataram" AND ("Application": "APIM" AND "Customer Code": "DJLFKASJF") OR ("Owner": "Vande Mataram" AND "Customer Code": "DJLFKASJF") OR "Owner": "Vande Mataram"';

console.log(filterData(Data, condition));
// 输出:第1、3、4条数据

优缺点

  • 优点:代码简单易实现,处理速度快
  • 缺点:如果条件字符串来自不可信来源(比如用户输入),存在代码注入风险,仅适用于条件可控的场景

方法二:递归解析条件表达式(安全可靠)

如果需要处理不可控的条件字符串,建议通过词法分析+语法分析构建抽象语法树(AST),再遍历AST进行条件判断,完全避免eval或动态函数的安全风险。

核心步骤

  1. 词法分析(Tokenize):将条件字符串拆分为可识别的标记(括号、运算符、键、值等)
  2. 语法分析(Parse):基于标记构建AST,处理嵌套括号和运算符优先级(AND优先级高于OR)
  3. 求值(Evaluate):遍历AST,对每个归一化后的 data item 进行条件判断

简化实现示例

// 归一化对象键名
function normalizeObj(obj) {
  const normalized = {};
  Object.keys(obj).forEach(key => {
    normalized[key.trim().toLowerCase()] = obj[key];
  });
  return normalized;
}

// 词法分析:生成tokens
function tokenize(conditionStr) {
  const str = conditionStr.replace(/"/g, '"');
  const tokens = [];
  let i = 0;
  const len = str.length;
  while (i < len) {
    const char = str[i];
    if (char === '(' || char === ')') {
      tokens.push({ type: 'PAREN', value: char });
      i++;
    } else if (/^\s$/.test(char)) {
      i++;
    } else if (char === '"') {
      i++;
      let strVal = '';
      while (i < len && str[i] !== '"') {
        strVal += str[i];
        i++;
      }
      tokens.push({ type: 'STRING', value: strVal });
      i++;
    } else if (str.slice(i, i+3) === 'AND') {
      tokens.push({ type: 'OPERATOR', value: 'AND' });
      i +=3;
    } else if (str.slice(i, i+2) === 'OR') {
      tokens.push({ type: 'OPERATOR', value: 'OR' });
      i +=2;
    } else if (char === ':') {
      tokens.push({ type: 'COLON', value: ':' });
      i++;
    } else {
      throw new Error(`无效字符: ${char} 位置: ${i}`);
    }
  }
  return tokens;
}

// 语法分析:构建AST
function parse(tokens) {
  let current = 0;
  
  function walk() {
    let token = tokens[current];
    
    // 处理括号包裹的子表达式
    if (token.type === 'PAREN' && token.value === '(') {
      current++;
      token = tokens[current];
      const node = { type: 'GROUP', expression: walk() };
      
      if (tokens[current].type !== 'PAREN' || tokens[current].value !== ')') {
        throw new Error('缺失闭合括号');
      }
      current++;
      return node;
    }
    
    // 处理键值判断条件
    if (token.type === 'STRING') {
      const key = token.value;
      current++;
      if (tokens[current].type !== 'COLON') {
        throw new Error('缺失冒号');
      }
      current++;
      if (tokens[current].type !== 'STRING') {
        throw new Error('值必须是字符串');
      }
      const value = tokens[current].value;
      current++;
      return { type: 'CONDITION', key: key.trim().toLowerCase(), value };
    }
    
    // 处理逻辑表达式
    let node = { type: 'EXPRESSION', left: walk(), operator: null, right: null };
    while (current < tokens.length && tokens[current].type === 'OPERATOR') {
      node.operator = tokens[current].value;
      current++;
      node.right = walk();
      // 处理运算符优先级:AND优先于OR,这里通过嵌套表达式实现
      if (node.operator === 'OR' && current < tokens.length && tokens[current].value === 'AND') {
        const temp = node;
        node = { type: 'EXPRESSION', left: temp.left, operator: temp.operator, right: walk() };
      }
    }
    return node;
  }
  
  const ast = walk();
  if (current !== tokens.length) {
    throw new Error('条件字符串解析不完整');
  }
  return ast;
}

// 求值:遍历AST判断数据项是否符合条件
function evaluate(ast, normalizedObj) {
  switch (ast.type) {
    case 'CONDITION':
      return normalizedObj[ast.key] === ast.value;
    case 'GROUP':
      return evaluate(ast.expression, normalizedObj);
    case 'EXPRESSION':
      const left = evaluate(ast.left, normalizedObj);
      const right = evaluate(ast.right, normalizedObj);
      if (ast.operator === 'AND') {
        return left && right;
      } else if (ast.operator === 'OR') {
        return left || right;
      }
      throw new Error(`未知运算符: ${ast.operator}`);
    default:
      throw new Error(`未知节点类型: ${ast.type}`);
  }
}

// 筛选函数
function safeFilterData(data, conditionStr) {
  try {
    const tokens = tokenize(conditionStr);
    const ast = parse(tokens);
    return data.filter(item => {
      const normalized = normalizeObj(item);
      return evaluate(ast, normalized);
    });
  } catch (err) {
    console.error('条件解析失败:', err);
    return [];
  }
}

// 测试
console.log(safeFilterData(Data, condition));
// 输出:第1、3、4条数据

优缺点

  • 优点:完全避免代码注入风险,支持复杂嵌套逻辑,适合不可控的条件输入场景
  • 缺点:实现复杂度较高,需要处理词法、语法分析的细节

内容的提问来源于stack exchange,提问作者Venkat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 13:54:52