公式和数学表达式解析算法
本文关键字:算法 表达式 | 更新日期: 2023-09-27 17:51:22
我必须编写一个能够解析公式的程序。它应该像下面的例子一样工作:
输入:5x + 7 ^ sin(z)/2T + 44
输出:输入x, z, t的值
输入:2、1、2
输出:答案是:something
应该支持(+,*,-,^,%,SIN, COS)
我确实读过分流码算法这一页
我也知道如何将中缀表达式转换为后缀或前缀。
这是我的算法:
1 -给出表达式。
2 -如果括号是平衡转到步骤3否则显示错误,转到步骤1
3 -求除(SIN)之外的所有变量,COS)
4 -从输入
5 -替换变量
6-在表达式前加上前缀并计算
7 -在输出中显示结果并关闭程序
对吗?我想在c#中实现它
请给我建议任何可能对我有用的注释
如果您决定从头开始编写,那么您的算法看起来不错。我将提供一些我的想法。
您可能希望将步骤5(替换变量)移动到步骤6(为表达式添加前缀并计算它)。换句话说,不只是对变量进行文本查找和替换,而是在需要计算变量时进行计算。这可以在以后打开更多的可能性,可能更容易绘制函数或具有依赖于其他变量的值的变量。不过,您的方法应该适用于简单的情况。
sin
和cos
函数的可能实现,使将来更容易定义其他函数,可以有一个Dictionary<string, Func<double,double>>
,类似于:
private var functions =
new Dictionary<string, Func<double,double>>(StringComparer.OrdinalIgnoreCase)
{
{ "sin", Math.Sin },
{ "cos", Math.Cos },
{ "sec", Secant }
};
. . .
// checking whether a token is a defined function or a variable
if (functions.ContainsKey(token))
{
// determine the value of the argument to the function
double inputValue = getArgument();
double result = functions[token](inputValue);
. . .
}
. . .
private static double Secant(double x)
{
return 1.0 / Math.Cos(x);
}
我不知道如何在c#中做到这一点,但是python有一个非常强大的语法树分析器(ast模块)可以在这里帮助你,如果你把表达式作为python表达式(这并不难,你只需要添加'*'乘法号:-))。
首先,定义只重新定义visit_Name
方法的好类(为标识符调用,例如另一个visit_Expr
为表达式调用,visit_Num
在满足数字时调用,等等,这里我们只想要标识符)。
>>> import ast
>>> class MyVisitor(ast.NodeVisitor):
def __init__(self, *args, **kwargs):
super(MyVisitor, self).__init__(*args, **kwargs)
self.identifiers = []
def generic_visit(self, node):
ast.NodeVisitor.generic_visit(self, node)
def visit_Name(self, node):
# You can specify othe exceptions here than cos or sin
if node.id not in ['cos', 'sin']:
self.identifiers.append(node.id)
然后定义一个快速函数,该函数接受一个表达式来给出它的标识符:
>>> def visit(expression):
node = ast.parse(expression)
v = MyVisitor()
v.visit(node)
print v.identifiers
看起来不错:
>>> visit('x + 4 * sin(t)')
['x', 't']
>>> visit('5*x + 7 ^ sin(z) / 2*T + 44')
['x', 'z', 'T']
ast模块使用python 2.6或2.7。