npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@nbxx/nb-expr-eval

v2.0.2001

Published

Mathematical expression evaluator originally created by Matthew Crumley

Downloads

8

Readme

JavaScript Expression Evaluator

This is a modified version of https://github.com/silentmatt/expr-eval 这是基于Matthew Crumley的expr-eval修改而成。

Description

处理数学表达式和有限的字符串、日期

支持的运算符、函数见后表

安装

npm install @nbxx/nb-expr-eval

基本用法

    var Parser = require('@nbxx/nb-expr-eval').Parser;

    var parser = new Parser();
    var expr = parser.parse('2 * x + 1');
    console.log(expr.evaluate({ x: 3 })); // 7

    // or
    Parser.evaluate('6 * x', { x: 7 }) // 42

使用文档

解析器

核心,包含 parse 方法及一些静态方法用于解析表达式。

Parser()

构造一个新的 Parser 实例。

构造器可以接受一个可选的 options 参数。

下面的例子会创建一个不允许比较,也不允许逻辑运算符,但允许 in 运算符的解析器:

    var parser = new Parser({
      operators: {
        // 默认开启,也可以手动关闭
        add: true,
        concatenate: true,
        conditional: true,
        divide: true,
        factorial: true,
        multiply: true,
        power: true,
        remainder: true,
        subtract: true,

        // 关闭逻辑运算,包含: and, or, not, <, ==, !=, 等等
        logical: false,
        comparison: false,

        // 关闭 in 以及 = 操作符
        'in': false,
        assignment: false
      }
    });

parse(expression: string)

把表达式解析为 Expression 对象

Parser.parse(expression: string)

new Parser().parse(expression) 的静态等价方法

Parser.evaluate(expression: string, variables?: object)

使用 variables 对象中的变量和方法来解析、计算表达式

Parser.evaluate(expr, vars) 等价于 Parser.parse(expr).evaluate(vars).

Expression

Parser.parse(str) 返回一个 Expression 对象, Expression 对象与 js 函数很相似,实际上也可以被直接转换为函数。

evaluate(variables?: object)

使用 variables 中的变量来计算 expression 对象, 如果有变量未被解析,则抛出异常。

    js> expr = Parser.parse("2 ^ x");
    (2^x)
    js> expr.evaluate({ x: 3 });
    8

substitute(variable: string, expression: Expression | string | number)

使用 expression 来替换原有 expression 中的 variable

    js> expr = Parser.parse("2 * x + 1");
    ((2*x)+1)
    js> expr.substitute("x", "4 * x");
    ((2*(4*x))+1)
    js> expr2.evaluate({ x: 3 });
    25

simplify(variables: object)

使用 variables 来替换表达式中的变量,从而简化表达式。函数不会被替换和简化。

实际上simplify只是简单的把变量替换了一下,然后将常数直接计算出结果。 所以 ((2*(4*x))+1) 是没法直接简化的,除非替换 x 。但是 2*4*x+1 是可以简化的, 因为它等价于(((2*4)*x)+1), 所以 (2*4) 会被简化为 "8", 生成结果 ((8*x)+1).

    js> expr = Parser.parse("x * (y * atan(1))").simplify({ y: 4 });
    (x*3.141592653589793)
    js> expr.evaluate({ x: 2 });
    6.283185307179586

variables(options?: object)

列出当前表达式中尚未被简化替换的变量。.

    js> expr = Parser.parse("x * (y * atan(1))");
    (x*(y*atan(1)))
    js> expr.variables();
    x,y
    js> expr.simplify({ y: 4 }).variables();
    x

variables 默认只返回最顶层的变量,例如 Parser.parse(x.y.z).variables() 返回 ['x']。 如果希望获得细节,可以使用 { withMembers: true },随后 Parser.parse(x.y.z).variables({ withMembers: true }) 将会返回['x.y.z'].

symbols(options?: object)

获取尚未简化的变量,以及所有函数

    js> expr = Parser.parse("min(x, y, z)");
    (min(x, y, z))
    js> expr.symbols();
    min,x,y,z
    js> expr.simplify({ y: 4, z: 5 }).symbols();
    min,x

variables 相似, symbols 接受可选参数 { withMembers: true } 来显示对象成员.

toString()

将表达式转化为字符串 toString() 将自动添加括号。.

toJSFunction(parameters: array | string, variables?: object)

Expression 转换为js函数。 parameters 是参数名列表(Array),或者参数名字符串(逗号分隔的列表)

如果提供了可选参数 variables 表达式将会被简化。

    js> expr = Parser.parse("x + y + z");
    ((x + y) + z)
    js> f = expr.toJSFunction("x,y,z");
    [Function] // function (x, y, z) { return x + y + z; };
    js> f(1, 2, 3)
    6
    js> f = expr.toJSFunction("y,z", { x: 100 });
    [Function] // function (y, z) { return 100 + y + z; };
    js> f(2, 3)
    105

表达式语法

基本上和js语法差不多,除了部分运算符为数学表达式外。例如: ^ 运算符代表指数函数,而不是异或。

运算符优先级(从上到下依次递减)

运算符 | 相依性 | 说明 :----------------------- | :------------ | :---------- (...) | None | 分组 f(), x.y, a[i] | Left | 方法调用、成员变量访问、数组下标访问 ! | Left | 阶乘 ^ | Right | 乘方 +, -, not, sqrt, etc. | Right | 一元前置运算符 (列表见后文) *, /, % | Left | 乘以、除以、取余 +, -, || | Left | 加、减、列表合并 ==, !=, >=, <=, >, <, in | Left | 等于、不等于、大于等于、小于等于、大于、小于、"in" 作为中间运算符,代表左侧操作数在右侧操作数之内 and | Left | 逻辑 AND or | Left | 逻辑 OR x ? y : z | Right | 三元运算符 (if x then y else z) = | Right | 变量赋值 ; | Left | 表达式分隔符

"in" 和 = 两个运算符默认关闭,需要显式开启才能使用

    const parser = new Parser({
      operators: {
        'in': true,
        'assignment': true
      }
    });
    // 现在可以使用 'x in array' 和 'y = 2*x' 两种表达式了

一元运算符

解析器包含一些内置函数,实际上会作为一元运算符来使用。他们和预定义函数的区别是他们只接受一个参数, 而且不需要括号包围起来。包含括号的一元运算符优先级和函数一致,不包含括号的一元运算符优先级按运算符优先级来计算(低于 '^')。 例如,sin(x)^2 等价于 (sin x)^2, 而 sin x^2 等价于 sin(x^2)+- 两种一元运算符是例外,因为不存在对应的函数,所以优先级始终按运算符优先级来计算。

运算符 | 说明 :------- | :---------- -x | 负数 +x | 一元加号。可以将一个操作数转为数字类型 x! | 对于正整数是阶乘,对于非正整数是 gamma(x + 1) 。 abs x | x 的绝对值 acos x | 反余弦 x (in radians) acosh x | 反双曲余弦 x (in radians) asin x | 反正弦 x (in radians) asinh x | 反双曲正弦 x (in radians) atan x | 反正切 x (in radians) atanh x | 反双曲正切 x (in radians) cbrt x | 开三次方 x ceil x | 向上取整 x, 大于等于 x 的最小整数 cos x | 余弦 x (x is in radians) cosh x | 双曲余弦 x (x is in radians) exp x | 以 e 为底数的指数/反对数函数,等价于 e^x expm1 x | e^x - 1 floor x | 向下取整 x,小于等于 x 的最大的整数 length x | x 的字符串长度 ln x | x 的自然对数 log x | x 的自然对数 log10 x | x 的对数 (底数为 10 的对数) log2 x | x 的对数 (底数为 2 的对数) log1p x | (1+x) 的自然对数 not x | 逻辑 NOT round x | 舍入取整,使用四舍五入法 sign x | x 的正负。-1 代表负数、0 代表 0、1 代表 正数 sin x | 正弦 x (x is in radians) sinh x | 双曲正弦 x (x is in radians) sqrt x | 平方根,如果 x 为负数, 结果为 NAN tan x | 正切 x (x is in radians) tanh x | 双曲正切 x (x is in radians) trunc x | 直接取整,舍去小数部分。x 为正数时向下取整, x 为负数时向上取整

预定义函数

除了运算符外,还有一些预定义的函数。预定义函数不会被 simplify 处理

函数 | 说明 :------------ | :---------- random(n) | 获取 [0,n) 之间的随机数,如果 n = 0,或者未提供 n ,则默认使用 1 代替 n fac(n) | n! (factorial of n: "n * (n-1) * (n-2) * … * 2 * 1") Deprecated. Use the ! operator instead. min(a,b,…) | 列表中最小的数字 max(a,b,…) | 列表中最大的数字 hypot(a,b) | 勾股定理。斜边长, a, b 分别指直角三角形的两个直角边,结果是直角三角形斜边长. pyt(a, b) | 等价于 hypot. pow(x, y) | 等价于 x^y atan2(y, x) | atan( x/y ). i.e. 坐标系中点 (0, 0) 到点 (x, y) 连线与x轴之间夹角. ( result is in radians) roundTo(x, n) | 将 x 四舍五入 n 位小数. map(f, a) | 列表映射。遍历列表 a 的每个元素 x,并计算 f(x) 作为新列表的元素值 fold(f, y, a) | 列表汇聚。遍历列表 a 的每个元素 x、序号 i,给定一个初始值,计算 f(y, x, i) 作为新列表的元素。最后计算新列表的和。 filter(f, a) | 列表筛选。遍历列表 a 的每个元素 x、序号 i,只保留 f(x, i) 为 true 的元素 indexOf(x, a) | 返回列表/字符串中第一个匹配的元素的下标,没有找到则返回 -1 join(sep, a) | 使用 sep 拼接 列表 a 中的全部字符串元素 if(c, a, b) | 三元运算符 c ? a : b 的 function 形式。但总会计算全部分支,如果对性能有要求应该直接使用三元运算符。 substr(str, start, length) | 获取字符串 str 中从 start 开始持续 length 个字符,如果不填 length 则获取从 start 开始到字符串结尾

列表处理

列表能直接使用 [] 定义,例如: [ 1, 2, 3, 2+2, 10/2, 3! ]

自定义函数

可以使用 name(params) = expression 的格式来自定义函数。函数支持多参数

Examples:

    square(x) = x*x
    add(a, b) = a + b
    factorial(x) = x < 2 ? 1 : x * factorial(x - 1)

自定义 js 函数

parser 有一个属性 functions ,记录了所有的函数。如果想要在全局的角度自定义函数,只需要添加即可

    const parser = new Parser();

    // Add a new function
    parser.functions.customAddFunction = function (arg1, arg2) {
      return arg1 + arg2;
    };

    // Remove the factorial function
    delete parser.functions.fac;

    parser.evaluate('customAddFunction(2, 4) == 6'); // true
    //parser.evaluate('fac(3)'); // This will fail

预定义常量

以下是预定义的常量:

常量 | 说明 :----------- | :---------- E | 等价于 js 的 Math.E PI | 等价于 js 的 Math.PI true | 逻辑 true false | 逻辑 false

与函数类似,预定义常量也保存在 parser 属性中。可以随意在 parser.consts 中添加自定义的常量。比如:

    const parser = new Parser();
    parser.consts.R = 1.234;

    console.log(parser.parse('A+B/R').toString());  // ((A + B) / 1.234)

To disable the pre-defined constants, you can replace or delete parser.consts:

    const parser = new Parser();
    parser.consts = {};

Tests

  1. cd to the project directory
  2. Install development dependencies: npm install
  3. Run the tests: npm test