0

Can someone explain why eval is returning the string, rather than the result of the expression?

perms=["12+2","22","-2+"]
perms.each { |line|
matches=/^[\d]+[+-\/\*]{1}[\d]+$/.match(line)
s=matches.to_a
puts s
puts eval(s.to_s)
} 
4
  • 2
    As an aside, in regular expressions [\d] is the same as \d and [+-\/\*]{1} is the same as [+-\/*], so your expression can be simplified to /^\d+[+-\/*]\d+/. Commented Jan 27, 2016 at 4:56
  • You should avoid eval. Instead, you could use /^(\d+)\+(\d+)$/ and calculate the result via $1.to_i + $2.to_i. Same for subtraction, multiplication and division. Commented Jan 27, 2016 at 7:06
  • @Stefan: if it's static data - why not? Commented Jan 27, 2016 at 7:18
  • @SergioTulentsev that's a crucial "if". I just see little to no reason to use potentially dangerous methods when safer alternatives exist. Commented Jan 27, 2016 at 7:47

2 Answers 2

3

s = matches.to_a is an array ["12+2"], the eval(s.to_s) will return the array ["12+2"], and when you print it, you will get the output 12+2, a string representation of the array ["12+2"].

You should be evaling the element of the array, in this case, s[0] or s.first.

Fix it like this:

perms=["12+2","22","-2+"]
perms.each do |line|
    matches=/^[\d]+[+-\/\*]{1}[\d]+$/.match(line)
    if matches
        s = matches.to_a
        puts eval(s.first)
    end
end

matches can be nil if there was no match. Use eval only if its not nil by checking if matches


You could further simplify the code and write something like this:

perms=["12+2","22","-2+"]
perms.each do |line|
    puts eval(line) if line =~ /^[\d]+[+-\/\*]{1}[\d]+$/
end
Sign up to request clarification or add additional context in comments.

2 Comments

Consider using String#scan instead of match to avoid check for nil. The former always returns an array, possibly empty.
Thanks for the simplified code, and the detailed explanation!
0

Instead of iterating through inputs, one might directly map them to outputs:

perms.map do |p|                      # map inputs to outputs
  eval(p) if p =~ /\A\d+[+-\/*]\d+\z/ # return eval’ed or nil
end.compact                           # get rid of nils

#⇒ [14]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.