2011-04-22 127 views
4

我必須編寫一個能夠解析公式的程序。 它應該工作像下面這個例子:公式和數學表達式解析器算法

輸入:5X + 7 ^罪(Z)/ 2T + 44
輸出:對於x,Z,T輸入值
輸入:2,1,2
輸出:答案是:什麼


應該支持(+,*, - ,^,%,SIN,COS)
我看過this頁關於調度場算法

而且我也知道如何將中綴表達式轉換爲後綴或前綴。
這是我的算法:

1 - 給予表達。
2 - 如果 括號是平衡轉到步驟3 別的顯示錯誤轉至步驟1
3 - 找到所有的變量除了(SIN, COS)
4 - 從 輸入給變量
5 - 更換變量 - 前綴表達並計算它
7 - 顯示結果在輸出 和關閉程序

是嗎?我想在C#中實現它#
請給我建議任何註釋可能對我有用。

+0

你可以使用ANTLR,看到這個[Q&A] (http://stackoverflow.com/questions/4396080/antlr-3-3-c-tutorials)。 – 2011-04-22 09:07:27

+1

[用於評估數學表達式的最佳算法?]的可能重複(http://stackoverflow.com/questions/572796/best-algorithm-for-evaluating-a-mathematical-expression) – 2011-04-22 10:05:03

回答

1

我不知道如何在C#中做到這一點,但蟒蛇擁有非常強大的語法樹分析(在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'] 

使用Python 2.6或2.7的AST模塊。

2

如果你決定從SCR寫atch,你的算法看起來不錯。我會提供一些我的想法。

您可能需要將步驟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); 
}