Flutter表达式计算插件tiny_expr的使用

发布于 1周前 作者 songsunli 来自 Flutter

Flutter表达式计算插件tiny_expr的使用

简介

TinyExpr 是一个轻量级的 Dart 表达式求值库,旨在从字符串中评估数学表达式。这使得它成为需要动态计算的应用程序的理想选择。

该项目灵感来自于C语言编写的 TinyExpr 库,原库可以在这里找到。我们对原作者的杰出工作表示感谢。

功能特性

  • 从字符串中评估数学表达式。
  • 支持基本算术运算:加法、减法、乘法和除法。
  • 支持括号以定义操作优先级。
  • 支持指数运算。
  • 支持一元取反。
  • 支持常数(如 pie)。
  • 支持三角函数(如 sincostancosecseccot)。
  • 支持双曲函数(如 sinhcoshtanh)。
  • 支持对数函数(如 logln)。
  • 支持平方根和绝对值。
  • 支持指数函数。
  • 支持舍入函数(如 ceilfloor)。
  • 支持阶乘、组合(nCr)和排列(nPr)。
  • 轻量且易于集成。
  • 支持在 String 上扩展方法以直接使用 .evaluate() 方法。

入门指南

要开始使用 TinyExpr,请在 pubspec.yaml 文件中添加它作为依赖项:

dependencies:
  tiny_expr: ^0.3.1

然后运行 flutter pub get 来安装该包。

使用方法

简单实现

以下是如何使用 TinyExpr 评估表达式的简单示例:

import 'package:tiny_expr/tiny_expr.dart';

void main() {
  final expression = '3 + 5 * (2 - 4)';
  final result = TinyExpr(expression).evaluate();
  print('Result: $result'); // Output: Result: -7
}

使用变量

以下是如何使用 TinyExpr 带有变量的示例:

import 'package:tiny_expr/tiny_expr.dart';

void main() {
  final expression = 'x + y * z';
  final te = TinyExpr(expression);
  te.addVariables({'x': 3.0, 'y': 2.0, 'z': 5.0});
  final result = te.evaluate();
  print('Result: $result'); // Output: Result: 13.0

  // 更新变量值
  te.updateVariables({'x': 10.0});
  final updatedResult = te.evaluate();
  print('Updated Result: $updatedResult'); // Output: Updated Result: 20.0
}

使用扩展方法

TinyExpr 现在支持在 String 上扩展方法以直接评估表达式:

import 'package:tiny_expr/tiny_expr.dart';

void main() {
  final expression = '3 + 5 * (2 - 4)';
  final result = expression.evaluate();
  final expressionWithVariables = 'x + y';
  final resultWithVariables =
      expressionWithVariables.evaluate(variables: {'x': 2, 'y': 15});
  print('Result: $result'); // Output: Result: -7
  print('Result: $resultWithVariables'); // Output: Result: 17
}

更多示例可以在 /example 文件夹中查看。

可用操作

操作类型 运算符/函数 示例
基本算术 +, -, *, /, % 2 + 3, 10 - 4, 6 * 7, 20 / 5, 8 % 3
指数运算 ^ 2^3
括号 () (2 + 3) * 4
一元取反 - -5, -(2 + 3)
常数 pi, e pi, e
三角函数 sin, cos, tan, cosec, sec, cot, atan2 sin(pi / 2), cos(pi), tan(pi / 4), cosec(pi / 2), sec(0), cot(pi / 4), atan2(1, 1)
双曲函数 sinh, cosh, tanh sinh(1), cosh(1), tanh(1)
对数函数 log, ln log(100), ln(e)
平方根 sqrt sqrt(16)
绝对值 abs abs(-5)
指数函数 exp exp(1)
舍入函数 ceil, floor ceil(2.1), floor(2.9)
阶乘 fac, ! fac(5), 5!
组合 ncr ncr(5, 3)
排列 npr npr(5, 2)

测试覆盖范围

TinyExpr 包含全面的测试,以确保表达式评估的正确性。测试涵盖以下内容:

  • 基本算术
  • 指数运算
  • 括号和优先级
  • 一元取反
  • 常数
  • 三角函数
  • 双曲函数
  • 对数函数
  • 平方根和绝对值
  • 指数函数
  • 舍入函数
  • 阶乘
  • 组合和排列
  • 变量处理
  • 嵌套表达式
  • 复杂表达式
  • 错误处理

文档覆盖范围

TinyExpr 包文档齐全,包含详细的功能说明、使用示例和 API 参考。文档涵盖以下部分:

  • 概述
  • 功能和限制
  • 入门指南
  • 使用示例
  • 可用操作
  • API 参考

未来计划

未来的计划包括:

  • 添加更多高级数学函数(如双曲三角函数、特殊函数)
  • 提高复杂表达式的性能
  • 添加用户自定义函数的支持
  • 增强错误处理和报告
  • 提供更多使用示例和文档
  • 添加更多数学常数的支持
  • 添加更多扩展方法

更多信息

更多信息请访问 TinyExpr GitHub 仓库

要为这个包做贡献,请提交 pull request 或者在 GitHub 上提交问题。我们欢迎贡献,并将尽快响应问题。

如果您遇到任何问题或有任何疑问,请随时在 GitHub 上提交问题,我们将尽力提供及时的帮助。

示例代码

以下是完整的示例代码,用于测试 TinyExpr 的各种功能:

import 'dart:math';
import 'package:tiny_expr/tiny_expr.dart';

void main() {
  // 测试 TinyExpr 评估器,给定表达式和预期结果
  void testExpression(String expression, double expected,
      {bool approx = false}) {
    try {
      final te = TinyExpr(expression);
      final result = te.evaluate();

      if (approx) {
        // 对于近似比较(例如浮点结果)
        if ((result - expected).abs() < 1e-6) {
          print("✅ Passed: $expression = $result (expected: $expected)");
        } else {
          print("❌ Failed: $expression = $result (expected: $expected)");
        }
      } else {
        // 对于精确比较
        if (result == expected) {
          print("✅ Passed: $expression = $result");
        } else {
          print("❌ Failed: $expression = $result (expected: $expected)");
        }
      }
    } catch (e) {
      print("❌ Failed: $expression threw an error: $e");
    }
  }

  // 运行所有测试
  print("Starting tests...\n");

  // 基本算术
  testExpression("2 + 3", 5.0);
  testExpression("10 - 4", 6.0);
  testExpression("6 * 7", 42.0);
  testExpression("20 / 5", 4.0);
  testExpression("8 % 3", 2.0);

  // 指数运算
  testExpression("2^3", 8.0);
  testExpression("5^0", 1.0);

  // 括号和操作优先级
  testExpression("(2 + 3) * 4", 20.0);
  testExpression("2 + 3 * 4", 14.0);
  testExpression("(2 + 3)^2", 25.0);

  // 一元取反
  testExpression("-5", -5.0);
  testExpression("-(2 + 3)", -5.0);

  // 常数
  testExpression("pi", pi, approx: true);
  testExpression("e", e, approx: true);

  // 三角函数
  testExpression("sin(pi / 2)", 1.0, approx: true);
  testExpression("cos(pi)", -1.0, approx: true);
  testExpression("tan(pi / 4)", 1.0, approx: true);
  testExpression("atan2(1, 1)", pi / 4, approx: true);
  testExpression("cosec(pi / 2)", 1.0, approx: true);
  testExpression("sec(0)", 1.0, approx: true);
  testExpression("cot(pi / 4)", 1.0, approx: true);

  // 双曲函数
  testExpression("sinh(1)", sinh(1.0), approx: true);
  testExpression("cosh(1)", cosh(1.0), approx: true);
  testExpression("tanh(1)", tanh(1.0), approx: true);

  // 对数函数
  testExpression("log(100)", 2.0);
  testExpression("ln(e)", 1.0, approx: true);

  // 平方根和绝对值
  testExpression("sqrt(16)", 4.0);
  testExpression("abs(-5)", 5.0);

  // 指数函数
  testExpression("exp(1)", e, approx: true);

  // 舍入函数
  testExpression("ceil(2.1)", 3.0);
  testExpression("floor(2.9)", 2.0);

  // 阶乘
  testExpression("fac(5)", 120.0);
  testExpression("fac(0)", 1.0);
  testExpression("fac(1)", 1.0);
  testExpression("5!", 120.0); // 阶乘运算符示例
  testExpression("0!", 1.0); // 阶乘运算符示例
  testExpression("1!", 1.0); // 阶乘运算符示例

  // 组合(nCr)和排列(nPr)
  testExpression("ncr(5, 3)", 10.0);
  testExpression("npr(5, 2)", 20.0);

  // 变量
  try {
    final teWithVars = TinyExpr("x + y * z");
    teWithVars.addVariables({"x": 3.0, "y": 2.0, "z": 5.0});
    final result = teWithVars.evaluate();
    if (result == 13.0) {
      print("✅ Passed: x + y * z with variables = $result");
    } else {
      print("❌ Failed: x + y * z with variables = $result (expected: 13.0)");
    }

    // 更新变量值
    teWithVars.updateVariables({"x": 10.0});
    final updatedResult = teWithVars.evaluate();
    if (updatedResult == 20.0) {
      print("✅ Passed: Updated x = $updatedResult");
    } else {
      print("❌ Failed: Updated x = $updatedResult (expected: 20.0)");
    }
  } catch (e) {
    print("❌ Failed: Variable tests threw an error: $e");
  }

  // 嵌套表达式
  testExpression("fac(3) + ncr(5, 2) * sqrt(16)", 6 + 10 * 4);

  // 复杂表达式
  testExpression("2 + 3 * (4 - 1)^2 / 2", 15.5);
  testExpression("5! + 3^2 - sqrt(16) * log(100)", 120.0 + 9 - 4 * 2);
  testExpression("sin(pi / 2) + cos(0) * tan(pi / 4)", 1.0 + 1.0 * 1.0,
      approx: true);
  testExpression("exp(1) + ln(e) - fac(3)", e + 1.0 - 6.0, approx: true);
  testExpression("ceil(2.1) + floor(2.9) * abs(-5)", 3.0 + 2.0 * 5.0);

  // 错误处理
  try {
    TinyExpr("unknown").evaluate();
    print("❌ Failed: Unknown variable/function should throw error");
  } catch (e) {
    print("✅ Passed: Unknown variable/function error handled: $e");
  }

  try {
    TinyExpr("5 +").evaluate();
    print("❌ Failed: Incomplete expression should throw error");
  } catch (e) {
    print("✅ Passed: Incomplete expression error handled: $e");
  }

  try {
    TinyExpr("log(-1)").evaluate();
    print("❌ Failed: log(-1) should throw error or return NaN");
  } catch (e) {
    print("✅ Passed: log(-1) error handled: $e");
  }

  print("\nAll tests completed!");
}

希望这些内容能帮助您更好地理解和使用 TinyExpr 插件!


更多关于Flutter表达式计算插件tiny_expr的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter表达式计算插件tiny_expr的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用tiny_expr插件来进行表达式计算的示例代码。tiny_expr是一个轻量级的数学表达式求值库,虽然它本身不是一个Flutter插件,但可以通过Dart的FFI(外部函数接口)或者通过平台通道与原生代码交互来使用。不过,为了简化示例,这里假设你已经有一个现成的Dart封装或者通过其他方式可以在Dart中调用tiny_expr的功能。

步骤 1: 添加依赖

首先,确保你的pubspec.yaml文件中添加了必要的依赖。由于tiny_expr不是直接可用的Flutter插件,你可能需要手动集成或者使用已有的Dart封装(如果有的话)。这里假设你已经有了某种方式可以在Dart中调用tiny_expr

步骤 2: 创建一个Flutter项目并集成表达式计算逻辑

假设你已经创建了一个Flutter项目,接下来我们将集成表达式计算逻辑。

main.dart

import 'package:flutter/material.dart';
import 'expression_evaluator.dart'; // 假设这是封装了tiny_expr功能的Dart文件

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Tiny Expr Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final TextEditingController _controller = TextEditingController();
  String _result = '';

  void _evaluateExpression() {
    String expression = _controller.text;
    try {
      double result = evaluateExpression(expression);
      setState(() {
        _result = 'Result: $result';
      });
    } catch (e) {
      setState(() {
        _result = 'Error: ${e.toString()}';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Tiny Expr Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextField(
              controller: _controller,
              decoration: InputDecoration(
                labelText: 'Enter Expression',
              ),
              keyboardType: TextInputType.multiline,
              maxLines: 5,
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _evaluateExpression,
              child: Text('Evaluate'),
            ),
            SizedBox(height: 20),
            Text(_result),
          ],
        ),
      ),
    );
  }
}

expression_evaluator.dart

这个文件封装了调用tiny_expr的逻辑(这里假设你已经有了某种方式调用它,实际实现可能涉及更多的原生代码集成)。

// 这是一个假设的封装,实际实现可能需要更多的原生代码集成
double evaluateExpression(String expression) {
  // 这里应该是调用tiny_expr的逻辑
  // 由于tiny_expr不是直接可用的Dart库,这里只是模拟一个简单的表达式求值
  // 实际的实现可能涉及调用C/C++代码或者通过FFI/平台通道
  // 假设表达式只包含基础的数学运算
  
  // 注意:以下代码仅为示例,不支持复杂的表达式解析和错误处理
  try {
    return double.parse(expression.replaceAll(RegExp(r'\s+'), '').replaceAll('x', '10').calculate());
  } catch (e) {
    throw Exception('Invalid expression');
  }
}

// 注意:上面的calculate()方法并不存在,这里只是为了演示
// 你需要实现一个真正的表达式解析和计算逻辑,可能通过tiny_expr或其他库

注意

  1. 实际集成:上面的expression_evaluator.dart文件只是一个占位符,实际中你需要实现与tiny_expr的交互逻辑。这可能涉及到使用Dart的FFI调用C/C++代码,或者通过平台通道与原生Android/iOS代码交互。

  2. 错误处理:在实际应用中,你需要添加更详细的错误处理逻辑,以处理各种可能的表达式错误。

  3. 性能:对于复杂的表达式,确保你的实现是高效的,特别是在移动设备上运行时。

  4. 安全性:确保你的表达式解析器是安全的,防止注入攻击等安全问题。

由于tiny_expr本身不是为Dart/Flutter设计的,因此集成它可能需要一些额外的工作。如果你不熟悉FFI或平台通道的使用,可能需要进一步学习这些技术。

回到顶部