欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

在这里插入图片描述

前言

在开发计算器、报表公式、甚至简单的脚本语言解释器时,我们往往需要让用户输入像 sin(x) + cos(y) * 2 这样的数学表达式,并在程序中动态求值。Dart 虽然这方面基础不错,但这需要词法分析、语法分析一系列复杂工作。

math_expressions 是一个强大的 Dart 数学表达式库,它支持解析字符串为抽象语法树 (AST),并能对表达式进行简化、求导和变量赋值计算。

一、概念介绍/原理解析

1.1 基础概念

  • Parser (解析器): 将 String 转换为 Expression 对象。
  • Expression (表达式): 可计算的节点(如 Number, Variable, Operator)。
  • Context (上下文): 存储变量值(如 x=10, y=5)用于求值。

解析器 (Parser)

求值计算

'x + 2 * y' (输入字符串)

抽象语法树 (AST)

加法 (Plus)

变量 x

乘法 (Times)

数值 2

变量 y

变量赋值: x=10, y=5

结果: 20

1.2 进阶概念

  • Simplification: 自动简化 x + 0x2 * 36
  • Derivation: 符号求导,甚至能算出 sin(x) 的导数是 cos(x)

二、核心 API/组件详解

2.1 基础用法

计算简单的四则运算字符串。

import 'package:math_expressions/math_expressions.dart';

void main() {
  Parser p = Parser();
  Expression exp = p.parse('(2 + 3) * 5');
  
  // 简化并求值
  ContextModel cm = ContextModel();
  double eval = exp.evaluate(EvaluationType.REAL, cm);
  
  print(eval); // 25.0
}

在这里插入图片描述

2.2 变量与函数

自定义变量值。

Parser p = Parser();
Expression exp = p.parse('x^2 + cos(y)');

ContextModel cm = ContextModel();
cm.bindVariable(Variable('x'), Number(3.0));
cm.bindVariable(Variable('y'), Number(0)); // cos(0)=1

double eval = exp.evaluate(EvaluationType.REAL, cm);
print(eval); // 3^2 + 1 = 10.0

在这里插入图片描述

三、常见应用场景

3.1 场景 1:科学计算器

用户输入公式,按下等于号。

String onEquals(String input) {
  try {
    Expression exp = parser.parse(input);
    return exp.evaluate(EvaluationType.REAL, cm).toString();
  } catch (e) {
    return 'Error';
  }
}

在这里插入图片描述

3.2 场景 2:数据绘图

给定函数 y = f(x),通过循环 x 取值计算一系列 y 点用于绘制曲线。

List<Point> generatePoints(Expression exp) {
  List<Point> points = [];
  for (double x = -10; x <= 10; x += 0.1) {
    cm.bindVariable(Variable('x'), Number(x));
    points.add(Point(x, exp.evaluate(EvaluationType.REAL, cm)));
  }
  return points;
}

3.3 场景 3:表单逻辑

类似于 Excel 公式,某些字段的值依赖于其他字段的计算结果。

// 总价 = 单价 * 数量 * 折扣
Expression formula = parser.parse('price * qty * discount');
cm.bindVariable(Variable('price'), Number(100));
cm.bindVariable(Variable('qty'), Number(2));
cm.bindVariable(Variable('discount'), Number(0.8));

在这里插入图片描述

四、OpenHarmony 平台适配

4.1 纯 Dart 实现

无平台依赖。

4.2 精度问题

Dart 的 double 遵循 IEEE 754 标准,存在浮点数精度问题(如 0.1 + 0.2 != 0.3)。对于金融计算,建议结合 decimal 库或自行处理精度。

五、完整示例代码

本示例构建一个允许用户输入任意数学公式并为变量 x 赋值的计算器。

import 'package:flutter/material.dart';
import 'package:math_expressions/math_expressions.dart';

void main() {
  runApp(const MaterialApp(home: MathPage()));
}

class MathPage extends StatefulWidget {
  const MathPage({super.key});

  
  State<MathPage> createState() => _MathPageState();
}

class _MathPageState extends State<MathPage> {
  final _formulaController = TextEditingController(text: 'x^2 + 2*x + 1');
  final _varController = TextEditingController(text: '5');
  String _result = '';

  void _calculate() {
    try {
      Parser p = Parser();
      Expression exp = p.parse(_formulaController.text);
      ContextModel cm = ContextModel();
      
      double xVal = double.tryParse(_varController.text) ?? 0;
      cm.bindVariable(Variable('x'), Number(xVal));

      double eval = exp.evaluate(EvaluationType.REAL, cm);
      
      setState(() => _result = '= $eval');
    } catch (e) {
      setState(() => _result = '错误: $e');
    }
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('公式计算器')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: _formulaController,
              decoration: const InputDecoration(
                labelText: '输入公式 (支持 x 变量)',
                hintText: '例如: sin(x) * 10',
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 10),
            TextField(
              controller: _varController,
              keyboardType: TextInputType.number,
              decoration: const InputDecoration(
                labelText: '变量 x 的值',
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: _calculate,
              child: const Text('计算结果'),
            ),
            const SizedBox(height: 20),
            Text(
              _result,
              style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.blue),
            ),
          ],
        ),
      ),
    );
  }
}

在这里插入图片描述

六、总结

math_expressions 让复杂的数学逻辑变得透明且可编程。它是教育软件、工程计算工具的理想基石。

最佳实践

  1. 预编译:如果公式不变但变量常变(如绘图),应只 parse 一次,重复调用 evaluate
  2. 错误提示:解析错误通常抛出异常,需捕获并友好提示用户(如“括号不匹配”)。
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐