Ruby用regex评估表达式,没有eval

时间:2013-04-14 00:22:18

标签: ruby regex eval

很抱歉,如果这是重复的话。我以为我会稍微改回一下我的问题。

我如何使用正则表达式来评估数学表达式?不使用eval函数。

示例表达式:

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

我希望它能在表达式中使用可变数量的数字,就像我在示例中所示。

4 个答案:

答案 0 :(得分:2)

这只是一个坏主意。 Regexp不是解析器,也不是评估器。

使用语法来描述你的表达。使用正式的解析器解析它,比如可爱的ruby gem Treetop。然后评估解析器生成的抽象语法树(AST)。

Gosh,Treetop的arithmetic example实际上为您提供免费的解决方案。

答案 1 :(得分:1)

这有点晚了,但是我写了一个用于评估任意数学表达式的宝石(并且它没有在内部使用eval):https://github.com/rubysolo/dentaku

答案 2 :(得分:0)

对于加法和减法,这应该有效

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

这意味着:

  • 一个或多个数字,后跟一个加号或减号
  • 以上可以根据需要重复多次(这是非捕获组)
  • 然后必须以一个或多个数字结尾。

请注意,每个单独的数字和符号都会在组1..n

中捕获

因此,为了评估,您可以捕获捕获1和3,应用捕获2中的符号。然后应用捕获4中的符号(如果存在)与先前结果和捕获5中的数字(如果捕获必须存在) 4存在)等......

所以要在psuedo代码中进行评估:

  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

这仅适用于您提供的示例中的简单加法和减法,因为它依赖于从左到右的关联性。正如其他人所建议的那样,你可能需要正确地解析任何更复杂的东西,例如通过构建一个节点树,然后可以以正确的(深度优先?)顺序进行评估。

答案 3 :(得分: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