Разбор синтаксиса разделенных запятыми в Rails

У меня есть файл, похожий на этот

ID Name  Car
1  Mike  Honda
2  Adam  Jim

Эти значения ограничены табуляцией, и из этого я хочу проанализировать ее в Ruby и поместить в мою базу данных.

Я пробовал следующее

require 'csv'

CSV.foreach("public/files/example.tab", {:col_sep => "\t"}) do |row|
  @stuff = row[0]
end

но @stuff просто возвращает весь весь объект и, похоже, не использует указанный разделитель столбцов.

Он также не учитывает, что первая строка является заголовком.

Как я могу разобрать файл с разделителями табуляции в Ruby и как я могу сказать, что первая строка является заголовком?

Ответ 1

У меня был успех с FasterCSV и Ruby 1.8.7, я считаю, что теперь ядро ​​csv-библиотеки в 1.9, используя это:

table = FasterCSV.read(result_file.to_file.path, { :headers => true, :col_sep => "\t", :skip_blanks => true })
unless table.empty?
    header_arry = Array.new
    table.headers.each do |h|
      #your header logic, e.g.
      # if h.downcase.include? 'pos'
        # header_arry << 'position'
      # end
      # simplest case here
      header_arry << h.downcase
      #which produces an array of column names called header_arry
    end

    rows = table.to_a
    rows.delete_at(0)
    rows.each do |row|
      #convert to hash using the column names
      hash = Hash[header_arry.zip(row)]
      # do something with the row hash
    end
  end

Ответ 2

Update

Посмотрите на Gem "smarter_csv" https://github.com/tilo/smarter_csv/; он имеет несколько интересных функций для создания хэшей из CSV-данных.

Предыдущий ответ

вот как я это сделаю (по пути я конвертирую "массивы массивов", которые возвращаются CSV.read или CSV.parse, в "массивы хешей"... это заставляет данные больше походить ActiveRecord, и это немного легче обработать таким образом позже..

require 'csv'

def process(csv_array)  # makes arrays of hashes out of CSV arrays of arrays
  result = []
  return result if csv_array.nil? || csv_array.empty?
  headerA = csv_array.shift             # remove first array with headers from array returned by CSV
  headerA.map!{|x| x.downcase.to_sym }  # make symbols out of the CSV headers
  csv_array.each do |row|               #    convert each data row into a hash, given the CSV headers
    result << Hash[ headerA.zip(row) ]  #    you could use HashWithIndifferentAccess here instead of Hash
  end
  return result
end

# reading in the CSV data is now just one line:

csv_data = process( CSV.read( filename , { :col_sep => "\t"}) )

 => [{:id=>"1", :name=>"Mike", :car=>"Honda"}, 
     {:id=>"2", :name=>"Adam", :car=>"Jim"}] 

теперь вы можете обрабатывать данные следующим образом:

csv_data.each do |hash|
  # ...
end

См. также:

http://as.rubyonrails.org/classes/HashWithIndifferentAccess.html

http://api.rubyonrails.org/classes/ActiveSupport/HashWithIndifferentAccess.html

Ответ 3

Я использовал простой способ для анализа данных csv. Здесь разделителями являются табуляция, пробел, запятая или точка с запятой. Он возвращает массив полей.

row_data = File.new("your_file.csv").read

row_data = row_data.split(/[ ,;\s]/).reject(&:empty?)