Как вы используете конвертеры Ruby CSV?
Предположим, что у вас есть следующий файл:
textfield,datetimefield,numfield
foo,2008-07-01 17:50:55.004688,1
bar,2008-07-02 17:50:55.004688,2
Код Ruby для чтения .csv выглядит примерно так:
#!/usr/bin/env ruby
require 'csv'
csv = CSV($stdin, :headers => true, :converters => :all)
csv.each do |row|
print "#{row}"
the_date = row['datetimefield'].to_date
end
Этот код дает следующее сообщение об ошибке:
./foo2.rb:8:in `block in <main>': undefined method `to_date' for "2008-07-01 17:50:55.004688":String (NoMethodError)
Что дает?
Я прочитал документы, но я не понимаю.
Изменить. Да, я мог бы анализировать поля отдельно. Дело в том, что я хочу узнать, как использовать функцию документированных конвертеров.
Ответы
Ответ 1
Время вашей даты не соответствует регулярному выражению CSV::DateTimeMatcher
, которое использует CSV, чтобы решить, следует ли пытаться преобразовать время. По внешнему виду он делает это из-за дробных секунд, которые у вас есть.
Вы можете либо перезаписать эту константу, либо написать свой собственный конвертер (DateTime.parse
кажется довольным вашими строками)
Ответ 2
Вы спрашиваете, как использовать преобразователи.
В моем примере определяется использование нового конвертера mytime
.
Конвертер my_time пытается построить объект времени, если это возможно.
#Define test data
src = <<csv
textfield,datetimefield,numfield
foo,2008-07-01 17:50:55.004688,1
bar,2008-07-02 17:50:55.004688,2
csv
require 'csv'
require 'time'
CSV::Converters[:mytime] = lambda{|s|
begin
Time.parse(s)
rescue ArgumentError
s
end
}
csv = CSV(src, :headers => true, :converters => [:mytime])
csv.each do |row|
print "#{row}"
the_date = row['datetimefield'].to_date
end
Используя этот метод, вы также можете определить конвертер для создания даты из временных строк. Это решение также поддерживает все другие преобразователи.
#define test data
src = <<csv
textfield,datetimefield,numfield
foo,2008-07-01 17:50:55.004688,1
bar,2008-07-02 17:50:55.004688,2
csv
require 'csv'
require 'time'
CSV::Converters[:time2date] = lambda{|s|
begin
Time.parse(s).to_date
rescue ArgumentError
s
end
}
csv = CSV(src, :headers => true, :converters => CSV::Converters.keys + [:time2date])
csv.each do |row|
print "#{row}"
p row['datetimefield'] #Date-field
end
Ответ 3
Работает!!! Исполняемая версия кода:
#Define test data
src =
"textfield,datetimefield,numfield\n" +
"foo,2008-07-01 17:50:55.004688,1\n" +
"bar,2008-07-02 17:50:55.004688,2"
require 'csv'
require 'time'
CSV::Converters[:mytime] = lambda{|s|
begin
Time.parse(s)
rescue ArgumentError
s
end
}
csv = CSV(src, :headers => true, :converters => [:mytime])
array_of_hash_objects = csv.to_a.map {|row| row.to_hash }
array_of_hash_objects.each do |row|
print "#{row}"
the_date = row['datetimefield'].to_date
puts
print the_date
puts
end
CSV::Converters[:time2date] = lambda{|s|
begin
Time.parse(s).to_date
rescue ArgumentError
s
end
}
csv = CSV(src, :headers => true, :converters => CSV::Converters.keys + [:time2date])
array_of_hash_objects = csv.to_a.map {|row| row.to_hash }
array_of_hash_objects.each do |row|
print "#{row}"
puts
p row['datetimefield'] #Date-field
end
=============
Выходы:
{"textfield"=>"foo", "datetimefield"=>2008-07-01 17:50:55 -0400, "numfield"=>"1"}
2008-07-01
{"textfield"=>"bar", "datetimefield"=>2008-07-02 17:50:55 -0400, "numfield"=>"2"}
2008-07-02
{"textfield"=>"foo", "datetimefield"=>2008-07-01 17:50:55 -0400, "numfield"=>1}
2008-07-01 17:50:55 -0400
{"textfield"=>"bar", "datetimefield"=>2008-07-02 17:50:55 -0400, "numfield"=>2}
2008-07-02 17:50:55 -0400