设计数学解析器最聪明的方法是什么?我的意思是一个函数,它接受一个数学字符串(如:“2 + 3/2 +(2 * 5)”)并返回计算值?我在VB6很久以前写过一个,但它最终变得臃肿而且不太便携(或者说很聪明......)。一般的想法,伪造的代码或真正的代码表示赞赏。

有帮助吗?

解决方案

一个相当不错的方法将涉及两个步骤。第一步涉及将表达式从中缀转换为后缀(例如通过 Dijkstra的调车场)表示法。完成后,编写 postfix评估器非常简单。

其他提示

我写了几篇关于设计数学解析器的博客文章。有一般的介绍,有关 grammars 用Ruby编写的示例实现测试套件。也许你会发现这些材料很有用。

你有几种方法。您可以生成动态代码并执行它以获得答案,而无需编写太多代码。只需在.NET中搜索运行时生成的代码,就会有很多例子。

或者,您可以创建一个实际的解析器并生成一个小的解析树,然后用于评估表达式。对于基本表达式,这也很简单。检查codeplex,因为我相信他们有一个数学解析器。或者只是查看BNF,其中包括示例。任何介绍编译器概念的网站都会将此作为基本示例。

Codeplex Expression Evaluator

我知道这已经过时了,但我遇到了这个尝试开发计算器作为更大的应用程序的一部分并使用接受的答案遇到一些问题。链接非常有助于理解和解决这个问题,不应该打折扣。我用Java编写了一个Android应用程序,并在表达式“string”中编写了每个项目。当用户在键盘上键入时,我实际上在StringList中存储了一个String。对于中缀到后缀的转换,我迭代遍历ArrayList中的每个String,然后评估新排列的字符串后缀ArrayList。对于少数操作数/运算符来说这是非常好的,但是更长的计算始终是关闭的,特别是当表达式开始评估为非整数时。在中缀到Postfix转换的提供链接中,它建议弹出如果扫描的项目是操作员且topStack项目具有更高的优先级,则为堆栈。我发现这几乎是正确的。如果topStack项的优先级高于或等于扫描的操作符,则弹出topStack项最终使我的计算结果正确。希望这将有助于解决这个问题的任何人,并感谢Justin Poliey(和fas?)提供一些宝贵的链接。

如果你有一个“永远在线”应用程序,只需将数学字符串发布到谷歌并解析结果。简单的方法,但不确定这是否是你需要的 - 但我猜想是聪明的。

相关问题具有优先权的公式(表达式)解析器?有一些很好的信息关于如何开始这个。

- 亚当

假设您的输入是字符串格式的中缀表达式,您可以将其转换为 postfix 并且,使用一对堆栈:运算符堆栈和操作数堆栈,从那里开始处理解决方案。您可以在Wikipedia链接中找到一般算法信息。

ANTLR是一个非常好的LL(*)解析器生成器。我高度推荐它。

开发人员总是想要一个干净的方法,并尝试从头开始实现解析逻辑,通常以 Dijkstra Shunting-Yard算法。结果是整洁的代码,但可能与bug有关。我已经开发了这样一个API, JMEP ,它完成了所有这些,但它花了我几年的时间有稳定的代码。

即使完成了所有这些工作,即使已经完成所有工作,即使从那个项目页面我也可以看到我正在认真考虑切换到使用JavaCC或ANTLR。

从问这个问题开始未来11年:如果你不想重新发明轮子,那里有许多奇特的数学解析器。

我在几年前写过一篇文章,它支持算术运算,方程求解,微积分,积分微积分,基本统计,函数/公式定义,图形等。

其名为 ParserNG 及其免费版。

评估表达式非常简单:

    MathExpression expr = new MathExpression("(34+32)-44/(8+9(3+2))-22"); 
    System.out.println("result: " + expr.solve());

    result: 43.16981132075472

或使用变量并计算简单表达式:

 MathExpression expr = new MathExpression("r=3;P=2*pi*r;"); 
System.out.println("result: " + expr.getValue("P"));

或使用功能:

MathExpression expr = new MathExpression("f(x)=39*sin(x^2)+x^3*cos(x);f(3)"); 
System.out.println("result: " + expr.solve());

result: -10.65717648378352

或者评估给定点的导数(注意它在幕后进行符号微分(非数值),因此精度不受数值近似误差的限制):

MathExpression expr = new MathExpression("f(x)=x^3*ln(x); diff(f,3,1)"); 
System.out.println("result: " + expr.solve());

 result: 38.66253179403897

在x = 3时区分 x ^ 3 * ln(x) 。 您可以区分的次数是1。

或数值整合:

MathExpression expr = new MathExpression("f(x)=2*x; intg(f,1,3)"); 
System.out.println("result: " + expr.solve());

result: 7.999999999998261... approx: 8

这个解析器非常快,并且具有许多其他功能。

通过绑定到Objective C将它移植到Swift已经完成了工作,我们已经在其他迭代用例中使用它来绘制应用程序。

免责声明:ParserNG由我撰写。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top