Подтвердить что ты не робот

Как вы используете конвертеры 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)

Что дает?

Я прочитал документы, но я не понимаю.

Изменить. Да, я мог бы анализировать поля отдельно. Дело в том, что я хочу узнать, как использовать функцию документированных конвертеров.

4b9b3361

Ответ 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