【问题标题】:Formula and math expression parser algorithm公式和数学表达式解析器算法
【发布时间】:2011-04-22 08:31:22
【问题描述】:

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

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


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

而且我还知道如何将中缀表达式转换为后缀或前缀。
这是我的算法:

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

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

【问题讨论】:

标签: c# algorithm math


【解决方案1】:

【讨论】:

    【解决方案2】:

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

    您可能希望将第 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);
    }
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-23
        • 2013-10-23
        • 2011-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多