公式和数学表达式解析器算法

时间:2011-04-22 08:31:22

标签: c# algorithm math

我必须编写一个能够解析公式的程序。 它应该像下面这个例子一样工作:

输入:5x + 7 ^ sin(z)/ 2T + 44
输出:输入x,z,t
的值 输入:2,1,2 输出:答案是:某事


它应该支持(+,*, - ,^,%,SIN,COS)
我确实阅读了关于Shunting-yard算法的this页面

我也知道如何将Infix表达式转换为后缀或前缀 这是我的算法:

  

1 - 给出表达式。
2 - 如果   括号是平衡转到第3步   否则显示错误转到步骤1
3 -   查找除(SIN,   COS)
4 - 给出变量   输入
5 - 替换变量
6    - 前缀表达式并计算它7 - 在输出中显示结果   并关闭程序

是吗?我想在C#中实现它。请建议我任何注释可能对我有用。

3 个答案:

答案 0 :(得分:8)

答案 1 :(得分:2)

如果您决定从头开始编写,您的算法看起来不错。我会提供一些我的想法。

您可能希望将步骤5(替换变量)移动到步骤6中(在表达式前加上并计算它)。换句话说,不是只对变量进行文本查找和替换,而是在计算期间在需要评估变量时进行。这可能会在以后开辟更多可能性,可能更容易绘制函数图形或使变量具有依赖于其他变量的值。不过,你的方式应该适用于简单的情况。

sincos函数的可能实现,使将来更容易定义其他函数,可能是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);
}

答案 2 :(得分:1)

我不知道如何在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。