2010-09-15 14 views
51

Tôi muốn phân tích cú pháp tệp CSV sao cho mỗi hàng được xử lý như đối tượng có hàng tiêu đề là tên của các thuộc tính trong đối tượng. Tôi có thể viết cái này, nhưng tôi chắc là nó đã ở đó rồi.Phân tích cú pháp tệp CSV với các trường tiêu đề làm thuộc tính cho mỗi hàng

Đây là đầu vào của tôi CSV:

"foo","bar","baz" 
1,2,3 
"blah",7,"blam" 
4,5,6 

Mã này sẽ giống như thế này:

CSV.open('my_file.csv','r') do |csv_obj| 
    puts csv_obj.foo #prints 1 the 1st time, "blah" 2nd time, etc 
    puts csv.bar  #prints 2 the first time, 7 the 2nd time, etc 
end 

Với mô-đun CSV Ruby Tôi tin rằng tôi chỉ có thể truy cập vào các lĩnh vực theo chỉ số. Tôi nghĩ rằng đoạn mã trên sẽ dễ đọc hơn một chút. Bất kỳ ý tưởng?

Trả lời

89

Sử dụng Ruby 1.9 trở lên, bạn có thể nhận được một một đối tượng lập chỉ mục:

CSV.foreach('my_file.csv', :headers => true) do |row| 
    puts row['foo'] # prints 1 the 1st time, "blah" 2nd time, etc 
    puts row['bar'] # prints 2 the first time, 7 the 2nd time, etc 
end 

Nó không chấm cú pháp nhưng nó rất đẹp để làm việc với hơn chỉ số.

Ngoài ra, đối với Ruby 1.8.x FasterCSV là những gì bạn cần để sử dụng cú pháp trên.

+0

FasterCSV nhanh chóng được tích hợp vào Ruby, tôi nghĩ nó nằm trong Ruby 1.9+. –

25

Dưới đây là ví dụ về cú pháp tượng trưng sử dụng Ruby 1.9. Trong các ví dụ bên dưới, mã đọc tệp CSV có tên data.csv từ thư mục db Rails.

:headers => true xử lý hàng đầu tiên làm tiêu đề thay vì hàng dữ liệu. Tham số :header_converters => :symbolize sau đó chuyển đổi từng ô trong hàng tiêu đề thành biểu tượng Ruby.

CSV.foreach("#{Rails.root}/db/data.csv", {:headers => true, :header_converters => :symbol}) do |row| 
    puts "#{row[:foo]},#{row[:bar]},#{row[:baz]}" 
end 

Trong Ruby 1.8:

require 'fastercsv' 
CSV.foreach("#{Rails.root}/db/data.csv", {:headers => true, :header_converters => :symbol}) do |row| 
    puts "#{row[:foo]},#{row[:bar]},#{row[:baz]}" 
end 

Dựa trên CSV được cung cấp bởi Poul (Asker StackOverflow), sản lượng từ các mã ví dụ trên sẽ là:

1,2,3 
blah,7,blam 
4,5,6 

Tuỳ trên các ký tự được sử dụng trong tiêu đề của tệp CSV, có thể cần thiết để xuất các tiêu đề để xem cách CSV (FasterCSV) chuyển đổi các tiêu đề chuỗi thành ký hiệu. Bạn có thể xuất mảng các tiêu đề từ trong số CSV.foreach.

row.headers 
+0

Vì vậy, tôi đã tải tệp CSV vào một mảng chỉ với 'allstocks << row' bên trong vòng lặp. Làm thế nào để đọc một ô 'myrow [: company]' trong đó 'myrow [: ticker] ==" ANAD "'? Chỉ có một bản ghi và 'ticker' là trường khóa của tôi. – Marcos

+0

Marcos - Nếu CSV đã được chuyển đổi thành một mảng, bạn có thể đã mất các băm (biểu tượng). Nếu đúng như vậy, chỉ cần tham chiếu ô theo số cột, ví dụ: myrow [0]. – scarver2

2

Mặc dù tôi khá muộn để thảo luận, một vài tháng trước, tôi đã bắt đầu "CSV cho đối tượng bản đồ" tại https://github.com/vicentereig/virgola.

Với nội dung CSV của bạn, lập bản đồ chúng vào một mảng của FooBar vật khá đơn giản:

"foo","bar","baz" 
1,2,3 
"blah",7,"blam" 
4,5,6 
require 'virgola' 

class FooBar 
    include Virgola 

    attribute :foo 
    attribute :bar 
    attribute :baz 
end 

csv = <<CSV 
"foo","bar","baz" 
1,2,3 
"blah",7,"blam" 
4,5,6 
CSV 

foo_bars = FooBar.parse(csv).all 
foo_bars.each { |foo_bar| puts foo_bar.foo, foo_bar.bar, foo_bar.baz } 
+0

Chỉ phát hiện ra rằng phần lớn trong số này có thể đạt được với các phương thức 'load' và' dump' (Ruby 1.9/FasterCSV) https://github.com/JEG2/faster_csv/blob/master/test/tc_serialization.rb –

+0

như thế này. Đó là một tính năng khá thú vị! https://gist.github.com/3188109 –

1

dễ dàng để có được một băm trong Ruby 2.3:

CSV.foreach('my_file.csv', headers: true, header_converters: :symbol) do |row| 
    puts row.to_h[:foo] 
    puts row.to_h[:bar] 
end 
0

Kể từ Tôi đã đặt câu hỏi này với một số tần suất:

array_of_hashmaps = CSV.read("path/to/file.csv", headers: true) 
puts array_of_hashmaps.first["foo"] # 1 

Đây là phiên bản không chặn, khi bạn muốn xóa toàn bộ tệp.

Các vấn đề liên quan