68 votes

Ruby analyse le fichier csv avec les champs d'en-tête en tant qu'attributs pour chaque ligne

J'aimerais analyser un fichier CSV de sorte que chaque ligne soit traitée comme un objet, l'en-tête-ligne étant le nom des attributs de l'objet. Je pourrais écrire ça, mais je suis sûr que ça existe déjà.

Voici mon csv

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

Donc, le code ressemblerait à quelque chose comme ça.

 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
 

Avec le module CSV de Ruby, je pense que je ne peux accéder aux champs que par index. Je pense que le code ci-dessus serait un peu plus lisible. Des idées? Merci!

115voto

Peer Allan Points 2217

Avec Ruby 1.9 et supérieur, vous pouvez récupérer un hachage au lieu d’un tableau comme celui-ci.

 CSV.foreach('my_file.csv', :headers => true) do |csv_obj|

  puts csv_obj['foo'] #prints 1 the 1st time, "blah" 2nd time, etc

  puts csv_obj['bar'] #prints 2 the first time, 7 the 2nd time, etc

end
 

Ce n'est pas une syntaxe à points, mais il est beaucoup plus agréable de travailler avec des index numériques.

En passant, Ruby 1.8.x FasterCSV est ce dont vous avez besoin pour utiliser la syntaxe ci-dessus.

37voto

scarver2 Points 2605

Voici un exemple de la symbolique de la syntaxe à l'aide de Ruby 1.9. Dans les exemples ci-dessous, le code lit un fichier CSV de données nommée.csv à partir de Rails de répertoire db. L' :headers => true traite de la première ligne comme en-tête, au lieu d'une ligne de données. L' :header_converters => :symboliser paramètre le convertit chaque cellule dans la ligne d'en-tête dans Ruby symbole.

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

En 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

Basé sur le CSV fourni par le Poul (le StackOverflow asker), la sortie à partir de l'exemple de code ci-dessus seront:

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

Selon les caractères utilisés dans les en-têtes du fichier CSV, il peut être nécessaire de sortie les en-têtes afin de voir comment CSV (FasterCSV) converti la chaîne des en-têtes de symboles, vous pouvez afficher le tableau d'en-têtes de dans le CSV.foreach.

row.headers

2voto

Vicente Reig Points 459

Bien que je sois assez en retard dans la discussion, il y a quelques mois, j'ai lancé un CSV pour mapper des objets à l' adresse https://github.com/vicentereig/virgola.

Compte tenu de votre contenu CSV, les mapper sur un tableau d'objets FooBar est assez simple.

 "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 }
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X