Ruby:解析,替换和评估字符串公式 [英] Ruby: Parse, replace, and evaluate a string formula

查看:75
本文介绍了Ruby:解析,替换和评估字符串公式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为一个朋友的心理调查项目创建一个简单的Ruby on Rails调查应用程序. 因此,我们有一个调查,每个调查都有很多问题,每个问题都有参与者可以选择的选项之一.没什么令人兴奋的.

I'm creating a simple Ruby on Rails survey application for a friend's psychological survey project. So we have surveys, each survey has a bunch of questions, and each question has one of the options participants can choose from. Nothing exciting.

有趣的方面之一是,每个答案选项都有与之相关的得分值. 因此,对于每个调查,都需要根据这些值来计算总分.

One of the interesting aspects is that each answer option has a score value associated with it. And so for each survey a total score needs to be calculated based on these values.

现在,我的想法不是硬编码计算,而是允许用户添加一个公式,通过该公式可以计算总调查得分.公式示例:

Now my idea is instead of hard-coding calculations is to allow user add a formula by which the total survey score will be calculated. Example formulas:

"Q1 + Q2 + Q3"
"(Q1 + Q2 + Q3) / 3"
"(10 - Q1) + Q2 + (Q3 * 2)"

所以只是基础数学(为清楚起见,还加上了一些括号).这样做的目的是使公式非常简单,以便具有基本数学知识的任何人都可以输入它们而无需解析某些花哨的语法.

So just basic math (with some extra parenthesis for clarity). The idea is to keep the formulas very simple such that anyone with basic math can enter them without resolving to some fancy syntax.

我的想法是采用任何给定的公式,并根据参与者的选择用分数值替换Q1,Q2等占位符.然后eval()新形成的字符串.像这样:

My idea is to take any given formula and replace placeholders such as Q1, Q2, etc with the score values based on what the participant chooses. And then eval() the newly formed string. Something like this:

f = "(Q1 + Q2 + Q3) / 2"  # some crazy formula for this survey
values = {:Q1 => 1, :Q2 => 2, :Q3 => 2}  # values for substitution 
result = f.gsub(/(Q\d+)/) {|m| values[$1.to_sym] }   # string to be eval()-ed
eval(result)

所以我的问题是:

  1. 是否有更好的方法来做到这一点? 我愿意接受任何建议.

  1. Is there a better way to do this? I'm open to any suggestions.

在并非全部情况下如何处理公式 占位符已成功替换(例如,一个 问题没有得到回答)?例如:{:Q2 => 2}不是 在值哈希?我的想法是营救eval(),但在这种情况下不会失败,因为coz (1 + + 2) / 2仍然可以通过eval()进行编辑……有什么想法吗?

How to handle formulas where not all placeholders were successfully replaced (e.g. one question wasn't answered)? Ex: {:Q2 => 2} wasn't in values hash? My idea was to rescue eval() but it wouldn't fail in this case coz (1 + + 2) / 2 can still be eval()-ed... any thoughts?

如何获得适当的结果?应该为2.5,但由于整数运算,它将截断为2.我不能指望提供正确公式(例如/2.0)的人理解这一细微差别.

How to get proper result? Should be 2.5, but due to integer arithmetic, it will truncate to 2. I can't expect people who provide the correct formula (e.g. / 2.0 ) to understand this nuance.

我不希望这样,但是如何 最好保护eval()免受滥用(例如 错误的公式,可操纵的价值 进来)?示例:f = 'system("ruby -v"); (Q1 + (Q2 / 3) + Q3 + (Q4 * 2)) / 2 '

I do not expect this, but how to best protect eval() from abuse (e.g. bad formula, manipulated values coming in)? Example: f = 'system("ruby -v"); (Q1 + (Q2 / 3) + Q3 + (Q4 * 2)) / 2 '

谢谢!

推荐答案

好的,现在完全安全了.我发誓!

OK, now it's totally safe. I swear!

我通常会克隆formula变量,但是在这种情况下,因为您担心敌对用户,所以我就地清除了该变量:

I would normally clone the formula variable but in this case since you're worried about a hostile user I cleaned the variable in place:

class Evaluator

  def self.formula(formula, values)
    # remove anything but Q's, numbers, ()'s, decimal points, and basic math operators 
    formula.gsub!(/((?![qQ0-9\s\.\-\+\*\/\(\)]).)*/,'').upcase!
    begin
      formula.gsub!(/Q\d+/) { |match|
        ( 
          values[match.to_sym] && 
          values[match.to_sym].class.ancestors.include?(Numeric) ?
          values[match.to_sym].to_s :
          '0'
        )+'.0'
      }
      instance_eval(formula)
    rescue Exception => e
      e.inspect
    end
  end

end

f = '(q1 + (q2 / 3) + q3 + (q4 * 2))'  # some crazy formula for this survey
values = {:Q2 => 1, :Q4 => 2}  # values for substitution 
puts "formula: #{f} = #{Evaluator.formula(f,values)}"  
=> formula: (0.0 + (1.0 / 3) + 0.0 + (2.0 * 2)) = 4.333333333333333

f = '(Q1 + (Q2 / 3) + Q3 + (Q4 * 2)) / 2'  # some crazy formula for this survey
values = {:Q1 => 1, :Q3 => 2}  # values for substitution 
puts "formula: #{f} = #{Evaluator.formula(f,values)}"  
=> formula: (1.0 + (0.0 / 3) + 2.0 + (0.0 * 2)) / 2 = 1.5

f = '(Q1 + (Q2 / 3) + Q3 + (Q4 * 2)) / 2'  # some crazy formula for this survey
values = {:Q1 => 'delete your hard drive', :Q3 => 2}  # values for substitution 
puts "formula: #{f} = #{Evaluator.formula(f,values)}"  
=> formula: (0.0 + (0.0 / 3) + 2.0 + (0.0 * 2)) / 2 = 1.0

f = 'system("ruby -v")'  # some crazy formula for this survey
values = {:Q1 => 'delete your hard drive', :Q3 => 2}  # values for substitution 
puts "formula: #{f} = #{Evaluator.formula(f,values)}"  
=> formula: ( -) = #<SyntaxError: (eval):1: syntax error, unexpected ')'>

这篇关于Ruby:解析,替换和评估字符串公式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆