Как изменить заголовки в файле CSV с помощью FasterCSV, а затем сохранить новые заголовки? - PullRequest
3 голосов
/ 02 июня 2009

У меня проблемы с пониманием: header_converters и: преобразователи в FasterCSV. По сути, все, что я хочу сделать, это изменить заголовки столбцов на соответствующие имена столбцов.

что-то вроде:

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 Я не понимаю: символ и: все в параметрах преобразователя.

Ответы [ 3 ]

9 голосов
/ 02 июня 2009

Преобразователь :all означает, что он пробует все встроенные преобразователи, в частности:

: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.

По сути, это означает, что он будет пытаться преобразовать любое поле в эти значения (если это возможно) вместо того, чтобы оставлять их в виде строки. Поэтому, если вы сделаете row[i] и он вернет строковое значение '9', он вместо этого вернет целочисленное значение 9.

Преобразователи заголовков изменяют способ использования заголовков для индексации строки. Например, если вы делаете что-то вроде этого:

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

Вы бы проиндексировали столбец с заголовком «Some Header» как row['some header'].

Если бы вы использовали :symbol вместо этого, вы бы проиндексировали его с row[:some_header]. Символ пресекает имя заголовка, заменяет пробелы подчеркиванием и удаляет символы, отличные от a-z, 0-9 и _. Это полезно, потому что сравнение символов намного быстрее, чем сравнение строк.

Если вы хотите проиндексировать столбец с помощью row['Some Header'], просто не указывайте параметр :header_converter.


EDIT:

В ответ на ваш комментарий, я боюсь, headers_convert не будет делать то, что вы хотите. Это не меняет значения строки заголовка, только то, как они используются в качестве индекса. Вместо этого вам придется использовать опцию :return_headers, определить строку заголовка и внести изменения. Чтобы изменить файл и записать его снова, вы можете использовать что-то вроде этого:

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

Если вам необходимо полностью заменить исходный файл, добавьте эту строку после выполнения вышеуказанного:

FileUtils.mv 'modified.csv', 'original.csv', :force => true
1 голос
/ 16 июля 2016

Я нашел простой подход к решению этой проблемы. Библиотека FasterCSV работает просто отлично. Я уверен, что ~ 7 лет между тем, когда пост был создан, и до сих пор может иметь к этому какое-то отношение, но я подумал, что здесь стоит отметить.

При чтении CSV-файлов опция FasterCSV :header_converters, на мой взгляд, недостаточно хорошо документирована. Но вместо присвоения символа (header_converters: :symbol) можно назначить лямбду (header_converters: lambda {...}). Когда библиотека CSV читает файл, она преобразует заголовки, используя лямбду. Затем можно сохранить новый файл CSV, который отражает преобразованные заголовки.

Например:

options = {
  headers: true,
  header_converters: lambda { |h| HEADER_MAP.keys.include?(h.to_sym) ? HEADER_MAP[h.to_sym] : h }
}

table = CSV.read(FILE_TO_PROCESS, options)

File.open(PROCESSED_FILE, "w") do |file|
  file.write(table.to_csv)
end
0 голосов
/ 17 ноября 2017

Перезапись заголовков файлов CSV является распространенным требованием для всех, кто преобразует экспортированные файлы CSV в импорт.

Я обнаружил, что следующий подход дал мне то, что мне нужно:

lookup_headers = { "old": "new", "cat": "dog" } # The desired header swaps

CSV($>, headers: true, write_headers: true) do |csv_out|
  CSV.foreach( ARGV[0],
               headers: true, 
               # the following lambda replaces the header if it is found, leaving it if not...
               header_converters: lambda{ |h| lookup_headers[h] || h}, 
               return_headers: true) do |master_row|

    if master_row.header_row?
      # The headers are now correctly replaced by calling the updated headers
      csv_out << master_row.headers
    else
      csv_out << master_row
    end
  end
end

Надеюсь, это поможет!

...