我必须编写一个能够解析公式的程序。 它应该像下面这个例子一样工作:
输入: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#中实现它。请建议我任何注释可能对我有用。
答案 0 :(得分:8)
查看这些视频。这些视频都在C#中,并有很好的解释。
答案 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);
}
答案 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。