2013-04-14 97 views
1

對不起,如果這是重複的。我想我會稍微改正我的問題。Ruby用正則表達式評估表達式,沒有eval

如何使用正則表達式來評估數學表達式?不使用eval函數。

實施例的表達式:

math1 = "1+1" 
math2 = "3+2-1" 

我想它和用於數字表達式中的可變數量的工作像我在實施例表明。

+0

可能重複:// stackoverflow.com/questions/15994101/ruby-evalute-without-eval) – Hauleth

+0

所以只是數字和加/減?你爲什麼不寫一個解析器呢? – Blender

+0

@ŁukaszNiemier是的,我知道,它的一個稍微不同的問題..感謝檢查我雖然兄弟 – Tommy

回答

0

對於加和減,這應該工作

(?:(/d+)([-+]))+(/d+)

這意味着:

  • 一個或多個數字,後面正好跟一個正負
  • 上面可以重複根據需要多次(這是非捕獲組)
  • 然後必須以一個或多個數字結尾。

注意,每個單獨的數字和符號組中被捕獲1..1

所以評估,你可以採取捕獲1和3,從捕獲2.將符號然後從捕獲應用標誌4(如果存在的話),與之前的結果,並從捕獲5(如果Capture 4存在必須存在)的數量等等...

這樣評價,在僞代碼:

i=1 
    result=capture(i) 
    loop while i <= (n-2) (where n is the capture count): 
    If capture(i+1) == "-" // is subtraction 
     result = result - capture(i+2) 
    Else // is addition 
     result = result + capture(i+2) 
    End if 
    i = i + 2 
    End while 

這只是要w ork用於簡單的加法和減法,就像您提供的示例一樣,因爲它依賴於從左到右的關聯性。正如其他人所建議的那樣,您可能需要正確解析更復雜的任何東西,例如,構建一個節點樹,然後可以按正確的(深度優先?)順序進行評估。

+0

那麼會匹配它。評估它沒有評估呢? – Tommy

+0

@Tommy對不起,誤會了。已經用算法更新了答案。 – Sepster

0

這是真的很亂......

math2 = "12+3-4" 
    head, *tail = math2.scan(/(?<digits>\d+)(?<op>[\+\-\*\/])?/) 
    .map{|(digits,op)| 
    [digits.to_i,op] 
    } 
    .reverse 

    tail.inject(head.first){|sum,(digits,op)| 
    op.nil? ? 
     digits : 
     digits.send(op,sum) 
    } 
    # => 11 

你真的應該考慮parser雖然。

2

這只是一個壞主意。正則表達式不是解析器,也不是評估者。

使用語法來描述您的表達式。用像可愛的紅寶石寶石Treetop這樣的正式解析器解析它。然後評估解析器產生的抽象語法樹(AST)。

天哪,Treetop的arithmetic example實際上給你免費的解決方案。

+0

+1「這只是一個壞主意」。 +1「正則表達式不是解析器,也不是評估者」。 -1「使用語法來描述你的表達式」 - 由OP_are_ regular給出的例子,因此RegEx可以正確地描述這個(簡單的)語法,一個正式的解析器可能被視爲過度殺傷。 -1「Treetop的算術例子實際上免費爲您提供解決方案。」 - 看着這個語法,有證明是過度的。 1 + 1-1-1 = 0 :-) – Sepster

+0

啊來吧,@Sepster。當有人想要「解析表達式」時,有99%的時間他們最終意味着各種各樣的算術運算符,其優先級和括號不同 - 這是不規則的。它總是以眼淚結束,直到他們學會解析。這是已有50多年曆史的技術,我們需要停止抽出錯誤的工具。 – dbenhur

+0

同意。但是這個問題並沒有提到任何關於「解析表達式」的問題,相反,它的標題是「用_regex_評估一個表達式」,並且在它的正文中「我怎麼用_regex_來評估一個數學表達式?」。這並不是說我認爲它應該這樣做。只是它可以完成。順便說一句,因爲我以前從未見過Treetop。 – Sepster