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

Swift中基于NSExpression实现带IF逻辑的数据库字符串公式计算

解决Swift中NSExpression支持分支逻辑公式的方案

核心问题分析

你之前尝试的TERNARY表达式无效,是因为错误地将子公式用引号括起来——原生TERNARY()需要接收表达式而非字符串,引号会让NSExpression把它当成字符串字面量,无法执行计算。

可行方案

方案1:正确使用原生TERNARY表达式(推荐)

直接在数据库存储的公式中嵌套表达式,不用引号,同时改用带索引的占位符(如$1、$2)避免变量替换歧义。

代码示例

// 数据库存储的分支公式(支持多分支嵌套)
let dbFormula = "TERNARY($1 == 1, (($2*$3)-$4)/$5, TERNARY($1 == 2, (($2*$3)+$4)*$5, 0))"

// 输入值数组(按占位符索引对应:$1对应第一个值,$2对应第二个,以此类推)
let inputValues = [2.0, 5.0, 3.0, 2.0, 6.0]

// 将值绑定到字典,用于NSExpression解析
var variables = [String: Double]()
for (index, value) in inputValues.enumerated() {
    variables["$\(index+1)"] = value
}

// 计算表达式
do {
    let expression = NSExpression(format: dbFormula)
    guard let result = expression.expressionValue(with: variables, context: nil) as? Double else {
        throw NSError(domain: "FormulaEval", code: 1, userInfo: [NSLocalizedDescriptionKey: "表达式计算失败"])
    }
    print(result) // 输出 ((5*3)+2)*6 = 17*6 = 102
} catch {
    print(error.localizedDescription)
}

方案2:自定义分支函数(适配复杂CASE场景)

如果多分支嵌套TERNARY可读性差,可以自定义CASE()函数,在代码中解析后替换为对应表达式再计算。

代码示例

extension NSExpression {
    static func evaluateCaseFormula(_ formula: String, with values: [Double]) throws -> Double {
        var processedFormula = formula
        
        // 替换带索引的占位符
        for (index, value) in values.enumerated() {
            processedFormula = processedFormula.replacingOccurrences(of: "$\(index+1)", with: "\(value)")
        }
        
        // 解析CASE表达式:CASE(变量, 分支1值:分支1公式, 分支2值:分支2公式, default:默认公式)
        let caseRegex = try NSRegularExpression(pattern: "CASE\\((.*?),\\s*(.*?)\\)")
        guard let match = caseRegex.firstMatch(in: processedFormula, range: NSRange(processedFormula.startIndex..., in: processedFormula)) else {
            throw NSError(domain: "FormulaEval", code: 2, userInfo: [NSLocalizedDescriptionKey: "无效的CASE表达式"])
        }
        
        guard let varRange = Range(match.range(at: 1), in: processedFormula),
              let branchesRange = Range(match.range(at: 2), in: processedFormula) else {
            throw NSError(domain: "FormulaEval", code: 3, userInfo: [NSLocalizedDescriptionKey: "CASE表达式格式错误"])
        }
        
        let targetValue = try NSExpression(format: String(processedFormula[varRange])).expressionValue(with: nil, context: nil) as? Double ?? 0
        let branchesStr = String(processedFormula[branchesRange])
        let branches = branchesStr.components(separatedBy: ",")
        
        var selectedExprStr = "0" // 默认值
        for branch in branches {
            let parts = branch.components(separatedBy: ":").map { $0.trimmingCharacters(in: .whitespaces) }
            guard parts.count == 2 else { continue }
            
            if parts[0] == "default" {
                selectedExprStr = parts[1]
                break
            }
            
            let branchValue = Double(parts[0]) ?? 0
            if branchValue == targetValue {
                selectedExprStr = parts[1]
                break
            }
        }
        
        // 替换CASE为选中的表达式并计算
        processedFormula.replaceSubrange(Range(match.range, in: processedFormula)!, with: selectedExprStr)
        let finalExpr = NSExpression(format: processedFormula)
        guard let result = try finalExpr.expressionValue(with: nil, context: nil) as? Double else {
            throw NSError(domain: "FormulaEval", code: 4, userInfo: [NSLocalizedDescriptionKey: "最终表达式计算失败"])
        }
        return result
    }
}

// 用法示例
let caseFormula = "CASE($1, 1: (($2*$3)-$4)/$5, 2: (($2*$3)+$4)*$5, default: 0)"
let inputValues = [1.0,5.0,3.0,2.0,6.0]
do {
    let result = try NSExpression.evaluateCaseFormula(caseFormula, with: inputValues)
    print(result) // 输出 (15-2)/6 ≈2.1667
} catch {
    print(error.localizedDescription)
}

方案3:替换为更灵活的表达式解析库

如果NSExpression的限制太多,可以使用Swift轻量开源表达式解析库,这类库原生支持分支、函数等复杂语法,直接解析数据库存储的公式即可,无需额外预处理。

注意事项

  • 避免使用单个$作为占位符,改用带索引的$1、$2,防止多变量替换时出现顺序错误。
  • 存储公式时无需加引号,直接写原生表达式语法。
  • 复杂嵌套分支优先使用方案2或3,保证可读性和可维护性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 08:31:10