用javascript解析算术表达式

2024-01-05

有没有一种简单的方法,用javascript来转换以下表达式

e*((a*(b+c))+d)

变成类似的东西

multiply(e, add(multiply(a, add(b,c)), d))

表达式将存储在字符串中。我愿意接受任何可以避免我编写自己的解析器的解决方案(库、内置功能……)

EDIT:我应该明确指出我实际上不想使用multiply and add函数,这样做的目的是定义我自己的函数来替换multiply and add并对变量执行自定义操作


您尝试解析为抽象语法树的表达式是上下文无关表达式。这意味着您需要上下文无关语法才能解析它。那么让我们创建一个解析器。

为了简化解析,我们将分离词法分析阶段。因此,我们需要的第一件事是创建一个词法分析器。幸运的是,有很多方便的词法分析器库可用。我们将使用这个:

https://github.com/aaditmshah/lexer https://github.com/aaditmshah/lexer

这是词法分析器:

var lexer = new Lexer;

lexer.addRule(/\s+/, function () {
    /* skip whitespace */
});

lexer.addRule(/[a-z]/, function (lexeme) {
    return lexeme; // symbols
});

lexer.addRule(/[\(\+\-\*\/\)]/, function (lexeme) {
    return lexeme; // punctuation (i.e. "(", "+", "-", "*", "/", ")")
});

接下来我们创建一个解析器。我们将使用以下 Dijkstra 调车场算法的实现来进行解析:

https://gist.github.com/aaditmshah/6683499 https://gist.github.com/aaditmshah/6683499

所以这是解析器:

var factor = {
    precedence: 2,
    associativity: "left"
};

var term = {
    precedence: 1,
    associativity: "left"
};

var parser = new Parser({
    "+": term,
    "-": term,
    "*": factor,
    "/": factor
});

最后我们创建一个parse函数如下:

function parse(input) {
    lexer.setInput(input);
    var tokens = [], token;
    while (token = lexer.lex()) tokens.push(token);
    return parser.parse(tokens);
}

现在你只需调用parse以后缀表示法获取已解析的标记流:

var output = parse("e*((a*(b+c))+d)");
alert(output.join(" "));               // "e a b c + * d + *"

后缀形式的优点是你可以使用堆栈轻松地操作它:

  1. Push e到堆栈上。
  2. Push a到堆栈上。
  3. Push b到堆栈上。
  4. Push c到堆栈上。
  5. Pop b and c并推b + c到堆栈上。
  6. Pop a and b + c并推a * (b + c)到堆栈上。
  7. Push d到堆栈上。
  8. Pop a * (b + c) and d并推a * (b + c) + d到堆栈上。
  9. Pop e and a * (b + c) + d并推e * (a * (b + c) + d)到堆栈上。

同样,使用堆栈也可以轻松创建所需的输出。都是同样的步骤。您只需将不同的值推回堆栈以进行不同的操作。

看演示:http://jsfiddle.net/d2UYZ/2/ http://jsfiddle.net/d2UYZ/2/

Edit 1:我实在是太无聊了,所以我为你解决了这个问题:

var stack = [];

var operator = {
    "+": "add",
    "-": "subtract",
    "*": "multiply",
    "/": "divide"
};

parse("e*((a*(b+c))+d)").forEach(function (c) {
    switch (c) {
    case "+":
    case "-":
    case "*":
    case "/":
        var b = stack.pop();
        var a = stack.pop();
        stack.push(operator[c] + "(" + a + ", " + b + ")");
        break;
    default:
        stack.push(c);
    }
});

var output = stack.pop();

alert(output);

输出是(如您所料)字符串"multiply(e, add(multiply(a, add(b,c)), d))"。看演示:http://jsfiddle.net/d2UYZ/4/ http://jsfiddle.net/d2UYZ/4/

Edit 2:如果您需要评估表达式,您也可以轻松完成。您所需要的只是将符号映射到每个运算符的值和函数的上下文:

var stack = [];

var context = {
    "a": 1,
    "b": 2,
    "c": 3,
    "d": 4,
    "e": 5
};

var operator = {
    "+": function (a, b) { return a + b; },
    "-": function (a, b) { return a - b; },
    "*": function (a, b) { return a * b; },
    "/": function (a, b) { return a / b; }
};

parse("e*((a*(b+c))+d)").forEach(function (c) {
    switch (c) {
    case "+":
    case "-":
    case "*":
    case "/":
        var b =+ stack.pop();
        var a =+ stack.pop();
        stack.push(operator[c](a, b));
        break;
    default:
        stack.push(context[c]);
    }
});

var output = stack.pop();

因此表达式e*((a*(b+c))+d)变成5*((1*(2+3))+4)其评估结果为45。看演示:http://jsfiddle.net/d2UYZ/6/ http://jsfiddle.net/d2UYZ/6/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用javascript解析算术表达式 的相关文章

  • 将值设置为输入字段时,西班牙语文本无法正确显示

    我正在尝试将西班牙语文本设置到输入字段 但它似乎没有正确显示 但是 如果相同的文本位于 div 内部或已设置为输入字段的值 则该文本可以正常显示 HTML div Cuenta de Ahorros Persona F iacute sic
  • 从 JavaScript 加载图像

    在我的专辑幻灯片放映页面上 我有类似的代码 span style display none img src imageUrl span span show loader span in showImage 我确定图像已加载 因此我显示图像并
  • 如何解决 FParsec 错误“组合器‘许多’已应用于解析器,该解析器在不消耗...的情况下成功”

    我有一个看起来足够简单的解析器 我将此子解析器添加到末尾以提供有关一般解析错误的信息 因为所有其他子解析器都失败了 Read the rest of a line as an error let readError parse let re
  • Mongoose 查询执行后回调函数从未被调用

    以下是我的代码 mongoose connect mongodb localhost mydatabase var db mongoose connection db on error console error bind console
  • 多次训练brain.js?

    在第一次训练后 如何将新信息 仅新信息 而不是所有信息 因为这会花费太多性能 训练到我的用 Brain js 制作的神经网络 它有点粗糙 但您可以使用以下结构来实现 如果我们加入 2 个训练数据集 旧数据集与新数据集 然后重新训练keepN
  • 如何使传单圆圈标记可拖动?

    使用传单 我创建了一个L circleMarker我希望它是可拖动的 var marker L circleMarker new L LatLng 48 94603 2 25912 draggable true bindPopup Circ
  • 有没有办法在 React 中自动播放音频而不使用 onClick 事件?

    我在尝试在 componentDidMount 中播放音频时收到此错误 未捕获 承诺中 DOMException play 失败 因为用户没有先与文档交互 componentDidMount document getElementById
  • 如何用 JavaScript 修复图像透视变形和旋转?

    我有一些用手机拍摄的图像 有没有可以拉直纸张照片并将其压平的 JavaScript 库 例如 我想创建一个矩形图像 该图像没有任何失真 换句话说我想知道如何用 JavaScript 修复透视变形和旋转 例如 我发现下面的示例图像来自this
  • setTimeout范围问题

    我在控制玩家重生的函数内部定义了一个 setTimeout 我正在创建一个游戏 var player death function this alive false Console log death var timer3 setTimeo
  • vuejs 模板和 asp.net 部分视图,好的做法吗?

    我在网站中使用 Vue js 并将模板添加到 html 代码中 并将 js 代码添加到单个 js 文件中 所以我不想使用 vue Vuefy Browserfy 方法 而是稍后捆绑并缩小我的 js 文件 由于我必须使用 Asp Net MV
  • 对使用“new”创建的数组上“map”的行为感到困惑[重复]

    这个问题在这里已经有答案了 我对结果感到困惑mapping 使用创建的数组new function returnsFourteen return 14 var a new Array 4 gt undefined x 4 in Chrome
  • jquery 中可点击 div 中的按钮

    我有整个 div 您可以单击它来切换该 div 的主要部分 问题是我在该 div 中也有可点击的按钮 当我点击它时 它会执行它应该做的事情 但同时也会切换整个 div 我怎样才能禁用它 Use event stopPropagation 单
  • IE localStorage 事件失火

    在 Internet Explorer 9 和 10 中 localStorage 实现意外地触发事件 这里有很棒的线索 Chrome 的 localStorage 实现存在错误 https stackoverflow com questi
  • 如何在 Javascript 中连接 C# ActiveX 事件处理程序

    我尝试使用几个代码片段将 ActiveX 对象与 Javascript 事件处理程序挂钩 我无法确定为什么事件处理程序没有被调用 带有项目的 Github 存储库 https github com JesseKPhillips Csharp
  • Javascript等待/异步执行顺序

    所以我试图把我的头脑集中在 Promise await async 上 我不明白为什么当 go 执行时 带有 finished 的警报会紧随 console log coffee 之后 当所有函数都使用等待 承诺时 为什么它只等待 getC
  • 如何使用 Javascript OAuth 库不暴露您的密钥?

    看着Twitter OAuth 库 https dev twitter com docs twitter libraries 我看到了这个注释 将 JavaScript 与 OAuth 结合使用时要小心 不要暴露你的钥匙 然后 看着jsOA
  • 如何将数据推送到嵌套对象

    如何将另一个元素推入variables来自以下对象的属性 var request name Name id 3 rules name Rule name tags tagId 1 variables variable var1 matchT
  • highchart堆积柱每个类别的总数据

    我想获取每个类别的总数据 这point stackTotal只给出活动数据的总数 从我粘贴的代码示例中 我想知道每种水果的总消耗量 因此 即使我单击右上角图例上的乔的名字 这使得堆叠图表上的所有乔信息都处于非活动状态 我仍然可以知道约翰 简
  • Html5画布最热门的任意形状

    我正在尝试开发可以在画布中渲染图像和文本的程序 我尝试处理画布中图像的点击 但它适用于可矩形图像 我的问题 您是否知道处理单击画布中图像的可见部分 非透明部分 的解决方案或框架 我正在寻找 ActionScript hitTestObjec
  • 如何从 Cloud Functions for Firebase 文件夹读取证书文件

    我正在尝试读取 certs 文件夹下的文件 如下所示 functions certs idp public cert perm 这是我用来读取文件的代码 fs readFileSync path join dirname certs idp

随机推荐