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

PHP构建查询时检测OR运算符序列并为其内容添加括号

解决方案:给连续OR条件自动添加分组括号

思路一:构建条件时维护OR分组(推荐)

直接在拼接条件的阶段就按AND/OR逻辑分组,从根源避免字符串处理的麻烦,这比事后正则替换更可靠,也不容易出现边界错误。

修改后的PHP代码

// 初始化分组(首次添加条件)
if (!isset($_SESSION['filter_groups_' . $c])) {
    // 处理第一个条件的NOT情况
    $initialCondition = $operator === "NOT" ? "NOT $selected_condition" : $selected_condition;
    // 用二维数组存分组:外层是AND连接的组,内层是OR连接的条件
    $_SESSION['filter_groups_' . $c] = [[$initialCondition]];
}

// 处理后续添加的条件
$validOperators = ['OR', 'OR NOT', 'AND', 'AND NOT'];
if (in_array($operator, $validOperators)) {
    $groups = $_SESSION['filter_groups_' . $c];
    
    if (str_starts_with($operator, 'AND')) {
        // AND开头的运算符:新建一个OR分组
        $condition = str_replace('AND ', '', $operator) . ' ' . $selected_condition;
        $groups[] = [$condition];
    } else {
        // OR开头的运算符:把条件加到最后一个OR分组里
        $condition = str_replace('OR ', '', $operator) . ' ' . $selected_condition;
        // 定位到最后一个分组
        end($groups);
        $lastGroupKey = key($groups);
        $groups[$lastGroupKey][] = $condition;
    }
    
    $_SESSION['filter_groups_' . $c] = $groups;
}

// 生成最终的WHERE子句
$groups = $_SESSION['filter_groups_' . $c];
$queryClauses = [];
foreach ($groups as $orGroup) {
    if (count($orGroup) === 1) {
        // 单个条件不需要括号
        $queryClauses[] = $orGroup[0];
    } else {
        // 多个OR条件用括号包裹
        $queryClauses[] = '(' . implode(' OR ', $orGroup) . ')';
    }
}
$finalWhereClause = 'WHERE ' . implode(' AND ', $queryClauses);

这个逻辑的核心是:

  • 用二维数组filter_groups保存结构:外层数组的每个元素是一组由OR连接的条件,组与组之间用AND连接
  • 当用户选择AND/AND NOT时,新建一个OR分组;选择OR/OR NOT时,把条件追加到当前最后一个OR分组
  • 最后拼接时,自动给包含多个条件的OR分组加上括号

思路二:正则替换处理已生成的字符串(备选)

如果不想修改原有构建逻辑,可以用正则对最终生成的WHERE子句做替换,但要注意条件文本中不能包含AND/OR这类关键字(否则会误匹配)。

正则替换代码

$originalWhere = "WHERE condition AND condition OR NOT condition AND condition OR condition OR condition";

// 第一步:给AND后面的OR组开头加左括号
$step1 = preg_replace('/AND\s+(?=(?:(?!AND\s).)*OR\s)/', 'AND (', $originalWhere);

// 第二步:给每个AND(非括号内的)前面加右括号
$step2 = preg_replace('/\s+AND\s+(?![^(]*\))/', ') AND ', $step1);

// 第三步:如果结尾是未闭合的OR组,补右括号
if (str_contains($step2, '(') && !str_ends_with(trim($step2), ')')) {
    $finalWhere = $step2 . ')';
} else {
    $finalWhere = $step2;
}

// 输出结果:WHERE condition AND (condition OR NOT condition) AND (condition OR condition OR condition)
echo $finalWhere;

正则说明

  • 第一个正则/AND\s+(?=(?:(?!AND\s).)*OR\s)/:匹配后面跟着OR条件的AND,替换成AND (
  • 第二个正则/\s+AND\s+(?![^(]*\))/:匹配不在括号内的AND,替换成) AND ,实现闭合前一个OR组
  • 最后补全结尾可能缺失的右括号

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 11:33:17