Найти тип содержимого (число, дата, время, строка и т. Д.) Внутри строки - PullRequest
5 голосов
/ 12 сентября 2009

Я пытаюсь проанализировать файл CSV и автоматически создать для него таблицу, используя команды SQL. Первая строка в CSV дает заголовки столбцов. Но мне нужно определить тип столбца для каждого.

Есть ли в Ruby функция, которая бы находила тип содержимого в каждом поле. Например, строка CSV:

"12012", "Test", "1233.22", "12:21:22", "10/10/2009"

должен производить такие типы, как

['integer', 'string', 'float', 'time', 'date']

Спасибо!

Ответы [ 3 ]

8 голосов
/ 13 сентября 2009
require 'time'

def to_something(str)
  if (num = Integer(str) rescue Float(str) rescue nil)
    num
  elsif (tm = Time.parse(str)) == Time.now
    # Time.parse does not raise an error for invalid input
    str
  else 
    tm
  end
end

%w{12012 1233.22 12:21:22 10/10/2009 Test}.each do |str|
  something = to_something(str)
  p [str, something, something.class]
end

Результаты в

["12012", 12012, Fixnum]
["1233.22", 1233.22, Float]
["12:21:22", Sat Sep 12 12:21:22 -0400 2009, Time]
["10/10/2009", Sat Oct 10 00:00:00 -0400 2009, Time]
["Test", "Test", String]

Обновление для ruby ​​1.9.3: класс Time в stdlib теперь вызывает исключение, если не может проанализировать строку, поэтому:

def to_something(str)
  duck = (Integer(str) rescue Float(str) rescue Time.parse(str) rescue nil)
  duck.nil? ? str : duck
end
1 голос
/ 12 сентября 2009

Это может помочь вам начать

У меня нет полного решения, но это может помочь вам начать. Вы можете перейти от примера к массиву объектов Class к строковому представлению автоматически, по крайней мере для некоторых типов, а затем перевести строки ...

$ irb
>> t = { "String" => "string", "Fixnum" => "integer", "Float" => "float" }
=> {"Float"=>"float", "Fixnum"=>"integer", "String"=>"string"}
>> ["xyz", 123, 123.455].map { |x| t[x.class.to_s] }
=> ["string", "integer", "float"]

Вы можете отобразить классы напрямую, на самом деле:

$ irb
>> t = { String => "string", Fixnum => "integer", Float => "float" }
=> {String=>"string", Float=>"float", Fixnum=>"integer"}
>> ["xyz", 123, 123.455].map { |x| t[x.class] }
=> ["string", "integer", "float"]
0 голосов
/ 29 апреля 2014

Если вы анализируете CSV, взгляните на это удивительное решение из Анализ CSV с Ruby

require 'csv'

CSV::Converters[:blank_to_nil] = lambda do |field|
  field && field.empty? ? nil : field
end

body = "col1,col2\nq,r\n1,2"
csv = CSV.new(body, :headers => true, :header_converters => :symbol, :converters => [:all, :blank_to_nil])
csv_hash = csv.to_a.map {|row| row.to_hash }

csv_hash.each do |row|
  puts row
  puts row.map{ |k,v|  v.class }.join(",")
end

выход

{:col1=>"q", :col2=>"r"}
String,String
{:col1=>1, :col2=>2}
Fixnum,Fixnum
...