#表达式解析器 #表达式 #数学 #解析器 #公式 #评估

exprtk_rs

Rust 对 C++ 库 ExprTk 的绑定 (http://www.partow.net/programming/exprtk)

4 个版本

0.1.0 2021年2月11日
0.0.7 2018年8月14日
0.0.5 2018年7月9日
0.0.4 2018年1月10日

2096Rust 模式

Download history 10/week @ 2024-03-30 3/week @ 2024-04-06 1/week @ 2024-04-20 1/week @ 2024-04-27

140 每月下载量

MIT 许可证

1.5MB
11K SLoC

C++ 9K SLoC // 0.0% comments Rust 1.5K SLoC // 0.0% comments

exprtk_rs

docs.rs Tests

Rust 对 ExprTk 库的绑定。

至少需要 Runst 版本 1.37。


lib.rs:

该软件包提供了对 ExprTk 库的绑定。

有关数据结构的概述,请参阅 ExprTk 主页。虽然 exprtk-sys 将库的大部分功能映射到 Rust,但高级绑定得到了显著简化。每个 Expression 都拥有一个 SymbolTable,它们不能在不同实例之间共享,并且每个表达式不可能有多个符号表。

变量属于 SymbolTable 实例。添加变量(add_variable())、字符串(add_stringvar())、向量(add_vector())的函数都返回 usize,这是一个表示内部数据结构中值索引的 变量ID。它可以用来稍后获取符号值和修改它们。标量可以通过可变引用或通过 std::cell::Cell 类型进行修改,而无需对 SymbolTable 进行可变访问。字符串使用 set_string() 进行修改,这需要可变访问。由于通过变量ID进行访问和修改需要边界检查,因此这些操作比C++中通过指针直接修改要慢。性能影响对于运行时间快的简单表达式更为明显,但在大多数情况下似乎并不成问题。运行 cargo bench 来查看影响(与不安全版本比较)。对于每种数据类型(标量、字符串和向量),访问ID从零开始,并在添加新变量时递增。

由于无法保证 double 总是 f64,因此库中所有地方都使用了 c_double 类型。目前不支持其他精度。

ExprTk 不处理非ASCII编码,因此变量名和公式会检查非ASCII字符或空字节,并且将出错。

示例

此代码对应于 ExprTk 文档中的 示例 1

use exprtk_rs::*;

let expression_string = "clamp(-1.0,sin(2 * pi * x) + cos(x / 2 * pi),+1.0)";

let mut symbol_table = SymbolTable::new();
symbol_table.add_constants();
let var_id = symbol_table.add_variable("x", 0.).unwrap().unwrap();

let mut expression = Expression::new(expression_string, symbol_table).unwrap();

// this value is a reference to a std::cell::Cell that can be changed
expression.symbols().value_cell(var_id).set(-5.);

while expression.symbols().value(var_id) <= 5. {
    let y = expression.value();
    println!("{}\t{}", expression.symbols().value(var_id), y);
    *expression.symbols_mut().value_mut(var_id) += 0.001;
}

未知变量

表达式中的未知变量可以自动添加到符号表中。函数 Expression::parse_vars 将返回一个包含新添加的变量名及其变量ID的 Vec。这仅适用于常规变量,不适用于字符串或向量。

use exprtk_rs::*;

let expr_string = "a*x^2 + b*x + c";

let (mut expr, unknown_vars) = Expression::parse_vars(expr_string, SymbolTable::new()).unwrap();

assert_eq!(
    unknown_vars,
    vec![("a".to_string(), 0), ("x".to_string(), 1), ("b".to_string(), 2), ("c".to_string(), 3)]
);

// modify the values
expr.symbols().value_cell(0).set(2.); // a
expr.symbols().value_cell(2).set(3.); // b
expr.symbols().value_cell(3).set(1.); // c
expr.symbols().value_cell(1).set(5.); // x

assert_eq!(expr.value(), 66.);

使用字符串的示例

use exprtk_rs::*;

let mut symbol_table = SymbolTable::new();
let s1_id = symbol_table.add_stringvar("s1", "Hello").unwrap().unwrap();
let s2_id = symbol_table.add_stringvar("s2",  "world!").unwrap().unwrap();

// concatenation
let mut expr = Expression::new("s1 + ' ' + s2 == 'Hello world!'", symbol_table).unwrap();
// a boolean `true` is represented by `1`
assert_eq!(expr.value(), 1.);

// Modifying a string
expr.symbols_mut().set_string(s1_id, "");
assert_eq!(expr.value(), 0.);

函数

目前可以添加具有最多十个标量参数的函数/闭包。示例

use exprtk_rs::*;

let mut symbol_table = SymbolTable::new();
symbol_table.add_func2("add", |x, y| x + y);
symbol_table.add_variable("x", 1.).unwrap();

let mut expr = Expression::new("add(x, 1)", symbol_table).unwrap();
assert_eq!(expr.value(), 2.);

依赖关系