2015-11-16 1 views
1

Я хочу, чтобы разобрать строки следующим образом:Как анализировать строки в своих типах данных?

"1.0" # => 1.0 (Float) 
"1" # => 1 (FixNum) 
"hello" # => "hello" (String) 
"true" # => true (TrueClass) 
"false" # => false (FalseClass) 

У меня есть следующий код:

def parse_value(val) 
    raise ArgumentError, "value must be a string" unless val.is_a? String 
    if val.to_i.to_s == val 
    val.to_i 
    elsif val.to_f.to_s == val 
    val.to_f 
    elsif val == 'true' 
    true 
    elsif val == 'false' 
    false 
    else 
    val 
    end 
end 

Это делает то, что нужно, но это кажется ужасным и неэффективным. Какой был бы лучший способ сделать это?

+0

Существует простой элегантный способ сделать то, что вы хотите с помощью метода 'е ** L'. Но я не решаюсь написать этот ответ, потому что в stackoverflow слишком много глупых пользователей, которые наверняка откажут такой ответ. – sawa

+0

@sawa Eval не будет работать для всех этих входов ('' hello "') –

+0

@SergioTulentsev Я пропустил это. Ты прав. На самом деле вопрос ОП неясен в этом вопросе. Как это приводит к строке? Когда это невозможно интерпретировать иначе? Если это так, это означает, что вы не можете иметь строку '' true '' и т. Д. – sawa

ответ

2

За исключением использования eval, вы не можете получить более сжатый/элегантный код, я боюсь. Вот вариант, используя case/when, но это губная помада на той же поросенке.

def parse_value(val) 
    raise ArgumentError, "value must be a string" unless val.is_a? String 
    case val 
    when /\A\d+\z/ 
    val.to_i 
    when /\A\d+(\.\d+)?\z/ 
    val.to_f 
    when 'true' 
    true 
    when 'false' 
    false 
    else 
    val 
    end 
end 
+0

Можете ли вы объяснить мне эти регулярные выражения, пожалуйста? – Steve

+1

@JohnLinux: они соответствуют целым числам и поплавковым номерам. Для получения дополнительной информации отправьте их на [http://regex101.com] (https://regex101.com/r/tE3tU3/1) или прочитайте свою любимую документацию по регулярному выражению. –

+0

+1 для regex101.com, очень полезно. Я знал, что они соответствуют номерам, более конкретно задавали теги. – Steve

1
def parse_value(val) 
    raise ArgumentError, "value must be a string" unless val.is_a? String 
    case val 
    when /\A\d+\z/   then val.to_i 
    when /\A\d+(\.\d+)?\z/ then val.to_f 
    when 'true'   then true 
    when 'false'   then false 
    else val 
    end 
end 

Я написал это в качестве более краткой версии ответа Sergios. Мне хотелось бы получить отзывы о том, будет ли это противоречить правилам стиля Ruby.

+1

Я лично не использую «тогда». Слишком много ввода (и необходимость их выравнивания) –

0

Вы можете использовать eval наряду с регулярным выражением:

def parse_string(val) 
    raise ArgumentError, "value must be a string" unless val.is_a? String 
    val =~ /\A(\d+(\.\d+)?|true|false)\z/ ? eval(val) : val 
end 

parse_string '1.0' #=> 1.0 
parse_string '1'  #=> 1 
parse_string 'hello' #=> "hello" 
parse_string 'true' #=> true 
parse_string 'false' #=> false 
0
def convert(s) 
    i = Integer(s) rescue nil 
    return i if i 
    f = Float(s) rescue nil 
    return f if f 
    return true if s == "true" 
    return false if s == "false" 
    s 
end 

arr = %w| 1 1.0 true false hello | 
    #=> ["1", "1.0", "true", "false", "hello"] 

arr.each { |s| e = convert(s); puts "#{e.class}: #{e}" } 
    # Fixnum: 1 
    # Float: 1.0 
    # TrueClass: true 
    # FalseClass: false 
    # String: hello