How do you change headers in a CSV File with FasterCSV then save the new headers?

btelles picture btelles · Jun 2, 2009 · Viewed 8.7k times · Source

I'm having trouble understanding the :header_converters and :converters in FasterCSV. Basically, all I want to do is change column headers to their appropriate column names.

something like:

FasterCSV.foreach(csv_file, {:headers => true, :return_headers => false, :header_converters => :symbol, :converters => :all} ) do |row|
    puts row[:some_column_header] # Would be "Some Column Header" in the csv file.

execpt I don't umderstand :symbol and :all in the converter parameters.

Answer

Pesto picture Pesto · Jun 2, 2009

The :all converter means that it tries all of the built-in converters, specifically:

:integer:   Converts any field Integer() accepts.
:float:     Converts any field Float() accepts.
:date:      Converts any field Date::parse() accepts.
:date_time: Converts any field DateTime::parse() accepts.

Essentially, it means that it will attempt to convert any field into those values (if possible) instead of leaving them as a string. So if you do row[i] and it would have returned the String value '9', it will instead return an Integer value 9.

Header converters change the way the headers are used to index a row. For example, if doing something like this:

FastCSV.foreach(some_file, :header_converters => :downcase) do |row|

You would index a column with the header "Some Header" as row['some header'].

If you used :symbol instead, you would index it with row[:some_header]. Symbol downcases the header name, replaces spaces with underscores, and removes characters other than a-z, 0-9, and _. It's useful because comparison of symbols is far faster than comparison of strings.

If you want to index a column with row['Some Header'], then just don't provide any :header_converter option.


EDIT:

In response to your comment, headers_convert won't do what you want, I'm afraid. It doesn't change the values of the header row, just how they are used as an index. Instead, you'll have to use the :return_headers option, detect the header row, and make your changes. To change the file and write it out again, you can use something like this:

require 'fastercsv'

input = File.open 'original.csv', 'r'
output = File.open 'modified.csv', 'w'
FasterCSV.filter input, output, :headers => true, :write_headers => true, :return_headers => true do |row|
  change_headers(row) if row.header_row?
end
input.close
output.close

If you need to completely replace the original file, add this line after doing the above:

FileUtils.mv 'modified.csv', 'original.csv', :force => true