How do you use Ruby CSV converters?

前端 未结 3 752
耶瑟儿~
耶瑟儿~ 2021-02-07 13:48

Suppose you have the following file:

textfield,datetimefield,numfield
foo,2008-07-01 17:50:55.004688,1
bar,2008-07-02 17:50:55.004688,2

The Rub

相关标签:
3条回答
  • 2021-02-07 14:37

    You are asking how to use converters.

    My example defines the usage of a new converter mytime. The converter my_time tries to build a time object if possible.

    #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
    

    Using this technique, you may also define a converter to create a date from time-like strings. This solution also keeps all other converters.

    #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
    
    0 讨论(0)
  • 2021-02-07 14:40

    Works!!! Executable version of code:

    #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
    

    =============

    Outputs:

    {"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
    
    0 讨论(0)
  • 2021-02-07 14:43

    Your date times don't match the CSV::DateTimeMatcher regexp that CSV uses to decide whether it should attempt a date time conversion. By the looks of it it's doing so because of the fractional seconds you've got.

    You could either overwrite that constant or write your own converter (DateTime.parse seems happy with your strings)

    0 讨论(0)
提交回复
热议问题