如何用XLFormula_engine计算数据库批量公式及生成向量结果?
使用XLFormula_engine处理数据库中的批量公式与变量计算需求
可以使用XLFormula_engine完美解决你的需求,不管是提取公式变量、批量计算还是处理复合公式,都能通过扩展现有逻辑实现。以下是具体实现方案:
一、提取公式中的变量(生成变量向量)
XLFormula_engine的解析模块会生成抽象语法树(AST),你可以遍历AST提取所有变量引用(即"A""B"这类标识)。示例实现如下:
use xlformula_engine::parse_formula::ast::{AstNode, AstNodeType}; // 遍历AST提取所有变量引用并去重 fn extract_variables(ast: &AstNode) -> Vec<String> { let mut variables = Vec::new(); match &ast.node_type { AstNodeType::CellReference(cell_ref) => { variables.push(cell_ref.to_string()); } AstNodeType::FunctionCall(_, args) => { // 递归处理函数参数中的变量 for arg in args { variables.extend(extract_variables(arg)); } } AstNodeType::BinaryOperation(left, _, right) => { // 处理二元运算两边的变量 variables.extend(extract_variables(left)); variables.extend(extract_variables(right)); } // 其他节点类型可按需扩展 _ => {} } // 去重并排序(可选) variables.sort_unstable(); variables.dedup(); variables }
二、适配数据库变量值表
将数据库存储的变量值表转换为data_function可查询的缓存结构,避免重复查询数据库:
use std::collections::HashMap; use xlformula_engine::types; // 从数据库加载变量值到HashMap(替换为你的实际数据库查询逻辑) fn load_variables_from_db() -> HashMap<String, types::Value> { let mut vars = HashMap::new(); vars.insert("A".to_string(), types::Value::Number(10.12)); vars.insert("B".to_string(), types::Value::Number(123.0)); vars.insert("C".to_string(), types::Value::Number(5.0)); vars } // 基于缓存的data_function实现 let var_map = load_variables_from_db(); let data_function = move |s: String| { var_map.get(&s).cloned().unwrap_or(types::Value::Error(types::Error::Value)) };
三、处理复合公式(带依赖的公式)
对于k=a/b、j=if(a>0,a/b,0)这类复合公式,需要先处理依赖顺序(先计算被依赖的公式,再计算依赖它的公式):
- 读取公式时记录每个公式的依赖变量(包括其他公式的输出)
- 构建依赖图并通过拓扑排序确定计算顺序
- 将已计算的公式结果加入变量缓存,供后续公式调用
示例代码片段:
use xlformula_engine::{calculate, parse_formula, NoCustomFunction}; // 从数据库读取的复合公式列表:(公式名称, 公式字符串) let compound_formulas = vec![ ("k".to_string(), "=A/B".to_string()), ("j".to_string(), "=IF(A>0,k,0)".to_string()), ]; // 初始化变量缓存(包含基础变量) let mut computed_vars = load_variables_from_db(); // 按依赖顺序计算(实际场景需通过拓扑排序确定顺序) for (var_name, formula_str) in compound_formulas { match parse_formula::parse_string_to_formula(&formula_str, None::<NoCustomFunction>) { Ok(formula) => { // 构建包含已计算变量的查询函数 let data_func = |s: String| { computed_vars.get(&s).cloned().unwrap_or(types::Value::Error(types::Error::Value)) }; // 计算公式结果 let result = calculate::calculate_formula(formula, Some(&data_func)).unwrap(); // 将结果加入缓存 computed_vars.insert(var_name.clone(), result.clone()); // 提取当前公式的变量向量 let variables = extract_variables(&formula.ast().unwrap()); // 输出结果 println!("公式{} | 变量向量: {:?} | 计算结果: {:?}", var_name, variables, result); } Err(e) => eprintln!("解析公式{}失败: {}", formula_str, e), } }
四、批量计算并输出向量
结合上述逻辑,批量处理数据库中的所有公式,输出每个公式的变量向量与计算结果:
// 从数据库读取的所有公式列表 let all_formulas = vec![ "=IF(A>0,B/A,0)".to_string(), "=A+B*C".to_string(), "=SUM(A,B,C)".to_string(), ]; let var_map = load_variables_from_db(); let data_function = move |s: String| { var_map.get(&s).cloned().unwrap_or(types::Value::Error(types::Error::Value)) }; for formula_str in all_formulas { match parse_formula::parse_string_to_formula(&formula_str, None::<NoCustomFunction>) { Ok(formula) => { let variables = extract_variables(&formula.ast().unwrap()); let result = calculate::calculate_formula(formula, Some(&data_function)); println!("变量向量: {:?} | 计算结果: {:?}", variables, result); } Err(e) => eprintln!("解析公式{}失败: {}", formula_str, e), } }
等价库选择
如果需要替代方案,Rust生态中的rust_xlsxwriter也支持公式计算,但XLFormula_engine更专注于独立的公式解析与计算,更适配你的场景。
内容的提问来源于stack exchange,提问作者zetaerre
相关产品推荐
相关产品推荐

