这不是学校作业或任何事情,但我意识到这是一个主要的学术问题.但是,我一直在努力做的是解析"数学"文本并提出答案.
例如 - 我可以弄清楚如何解析'5 + 5'或'3*5' - 但是当我尝试正确地将操作链接在一起时我失败了.
(5 + 5)*3
这大多只是让我烦恼,我无法弄明白.如果有人能指出我的方向,我真的很感激.
编辑 感谢您的所有快速回复.对不起,我没有更好地解释.
首先 - 我没有使用正则表达式.我也知道已有的库可以作为字符串使用数学表达式并返回正确的值.所以,我主要是看着这个,因为,遗憾的是,我并没有"明白".
第二 - 我尝试过的事情(可能是误入歧途),但我在计算'('和')'并首先评估最深的项目.在简单的例子中,这有效; 但我的代码不漂亮,更复杂的东西崩溃.当我'计算'最低级别时,我正在修改字符串.
所以...(5 + 5)*3
会变成10*3
然后评估为30
但它感觉"错了".
我希望这有助于澄清事情.我肯定会查看提供的链接.
在使用一个简单的图形应用程序时,我使用这个算法(相当容易理解并且对于像这样的简单数学表达式非常有效)首先将表达式转换为RPN,然后计算结果.RPN对于不同的变量值执行起来非常好而且快速.
当然,语言解析是一个非常广泛的主题,还有很多其他方法可以解决它(以及它的预制工具)
这是您想要的简单(朴素的运算符优先级)语法。
expression =
term
| expression "+" term
| expression "-" term .
term =
factor
| term "*" factor
| term "/" factor .
factor =
number
| "(" expression ")" .
Run Code Online (Sandbox Code Playgroud)
当您处理“因子”时,您只需检查下一个标记是数字还是“(”,如果它是“(”,那么您再次解析“表达式”,当表达式返回时,您检查下一个标记是否是“)”。您可以通过使用out或ref参数将 [calculated|read] 值向上冒泡到父级,或者构建表达式树。
这是 EBNF 中的相同内容:
expression =
term
{ "+" term | "-" term } .
term =
factor
{ "*" factor | "/" factor }.
factor =
number
| "(" expression ")" .
Run Code Online (Sandbox Code Playgroud)
@Rising Star [我希望将其添加为评论,但格式化失败]
这可能看起来有悖常理,但二叉树既简单又灵活。在这种情况下,节点可以是常量(数字)或运算符。当您决定使用控制流和函数等元素扩展语言时,二叉树会让生活变得更轻松。
例子:
((3 + 4 - 1) * 5 + 6 * -7) / 2
'/'
/ \
+ 2
/ \
* *
/ \ / \
- 5 6 -7
/ \
+ 1
/ \
3 4
Run Code Online (Sandbox Code Playgroud)
在上述情况下,扫描仪已被编程为读取“-”后跟一系列数字作为单个数字,因此“-7”作为“数字”标记的值组件返回。'-' 后跟空格作为“减号”标记返回。这使得解析器更容易编写。它在您想要“-(x * y)”的情况下失败,但您可以轻松地将表达式更改为“0 - exp”
对于任何在这篇文章发表九年后看到这个问题的人:如果你不想重新发明轮子,那么那里有很多奇特的数学解析器。
有一个是我几年前用 Java 写的,它支持算术运算、方程求解、微分、积分、基本统计、函数/公式定义、绘图等。
它被称为ParserNG并且是免费的。
评估表达式非常简单:
MathExpression expr = new MathExpression("(34+32)-44/(8+9(3+2))-22");
System.out.println("result: " + expr.solve());
result: 43.16981132075472
Run Code Online (Sandbox Code Playgroud)
或者使用变量并计算简单的表达式:
MathExpression expr = new MathExpression("r=3;P=2*pi*r;");
System.out.println("result: " + expr.getValue("P"));
Run Code Online (Sandbox Code Playgroud)
或者使用函数:
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
Run Code Online (Sandbox Code Playgroud)
或者评估给定点的导数(注意: 它在幕后进行符号微分(而不是数值),因此精度不受数值近似误差的限制):
MathExpression expr = new MathExpression("f(x)=x^3*ln(x); diff(f,3,1)");
System.out.println("result: " + expr.solve());
result: 38.66253179403897
Run Code Online (Sandbox Code Playgroud)
x^3 * ln(x)在 x=3 处微分一次。目前可以区分的次数为1。
或对于数值积分:
MathExpression expr = new MathExpression("f(x)=2*x; intg(f,1,3)");
System.out.println("result: " + expr.solve());
result: 7.999999999998261... approx: 8
Run Code Online (Sandbox Code Playgroud)
该解析器速度相当快,并且具有许多其他功能。
免责声明:ParserNG 是我创作的。