2013-12-22 2 views
1

У меня есть санированная строка, которую я хочу оценить, используя ruby ​​eval. Строка может содержать любую простую формулу арифметики, например '44/5 '.Ruby eval without round

Проблема в том, что результатом eval('44/5') будет 8 (вместо 8.8).

Это происходит в процессе оценки (потому что 1.0*eval('44/5') дает 8.0).

Я не нашел дополнительных параметров для eval для управления им.

Я даже пытался предписать или обернуть строку, чтобы преобразовать его в:

'0.0+44/5' 

или

'1.0*(44/5)' 

Но это еще не дает мне 8.8.

eval('44.0/5') дает мне желаемый результат, но я не хочу вставлять что-либо внутри строки (я готов просто обернуть его, если необходимо).

Любая идея, как я могу решить проблему?

ответ

4

Вы также можете использовать mathn from Ruby's core library:

require 'mathn' 

res = eval('44/5')  #=> (44/5) 
res.to_f    #=> 8.8 

Эта библиотека будет автоматически конвертировать в рациональных где это необходимо.

+0

это блестящий +1 для знания, думайте, что это нужно добавить в документацию ruby. – bjhaid

+0

@bjhaid Это в документах ;-) Я связан с ним. –

+0

Документы не объясняют, что вы получаете объект Rational (тип объекта), его непростой для некоторых существ, нужно было просто проверить pry/irb, чтобы узнать, что это был рациональный объект. – bjhaid

8

Здесь используется Rational#to_f:

Rational('44/5').to_f # => 8.8 
'44/5'.to_r.to_f # => 8.8 
+2

У строки есть 'to_r'method: '44 /5'.to_r – steenslag

+0

@steenslag Да ..' '44 /5'.to_r # => (44/5) ', но после этого' # to_f' требует быть вызванным. Во всяком случае, я добавил это также. Спасибо –

+0

Это не очень помогает в моем случае (поскольку я сказал, что строка может представлять любую арифметическую формулу, например «2 + 3/4») – Alexander

0

я не нашел каких-либо дополнительных параметров для Eval, чтобы управлять им.

Потому что eval предназначен для всех вещей, а не только для математических уравнений.

Arup-х solution выглядит лучше, но вот мое:

str = '4/5' 
eval('1.0*'+ str) #0.8 

пс. Вторая строка (1.0*(44/5)) не будет работать, потому что сначала оценивается (44/5) (8 = целое число), а затем умножается на 1.0 (= 8,0).

0

Не знаете, почему никто не упомянул об этом, чтобы заставить поплавок положить поплавок в делитель. то есть

eval('44/5') 
#=> 8 
eval('44/5.0') 
#=> 8.8 

Хотя, если вам не хватает контроля над строкой может быть более трудным, но это будет работать

eval('44/5'.split("/").map(&:to_f).join("/")) 
#=> 8.8 

для обработки множества символов arthimitic с помощью Eval

pattern = /([0-9]\.?[0-9]+|[0-9]+|[+-\/*\(\)])/ 
str = "2+3/4" 
str.scan(pattern).flatten.map{|e| e =~(/[0-9]/) ? e.to_f : e} 
#=> [2.0,"+",3.0,"/",4.0] 
str.scan(pattern).flatten.map{|e| e =~(/[0-9]/) ? e.to_f : e}.join 
#=> "2.0+3.0/4.0" 
eval(str.scan(pattern).flatten.map{|e| e =~(/[0-9]/) ? e.to_f : e}.join) 
#=> 2.75 

Работы со скобками слишком и существующие поплавки

str = "(2+3)/4" 
eval(str.scan(pattern).flatten.map{|e| e =~(/[0-9]/) ? e.to_f : e}.join) 
#=> 1.25 

str = "(2.3+1)/4" 
eval(str.scan(pattern).flatten.map{|e| e =~(/[0-9]/) ? e.to_f : e}.join) 
#=> 0.825 

Проблема с Rational методом

str = "(2.3+3)/4*2" 
str.to_r.to_f 
#=>0.0 
eval(str.scan(pattern).flatten.map{|e| e =~(/[0-9]/) ? e.to_f : e}.join) 
#=> 2.65 

Очень простой без дополнительных библиотек.

Смежные вопросы