Ubuntu 12.04 LTS
Ruby ruby 1.9.3dev (2011-09-23 révision 33323) [i686-linux]
Rails 3.2.9
Voici le contenu de mon fichier CSV reçu:
"date/time","settlement id","type","order id","sku","description","quantity","marketplace","fulfillment","order city","order state","order postal","product sales","shipping credits","gift wrap credits","promotional rebates","sales tax collected","selling fees","fba fees","other transaction fees","other","total"
"Mar 1, 2013 12:03:54 AM PST","5481545091","Order","108-0938567-7009852","ALS2GL36LED","Solar Two Directional 36 Bright White LED Security Flood Light with Motion Activated Sensor","1","Amazon.com","Amazon","Pasadena","CA","91104-1056","43.00","3.25","0","-3.25","0","-6.45","-3.75","0","0","32.80"
Cependant, lorsque j'essaie d'analyser le fichier CSV, une erreur se produit:
1.9.3dev :016 > options = { col_sep: ",", quote_char:'"' }
=> {:col_sep=>",", :quote_char=>"\""}
1.9.3dev :022 > CSV.foreach("/tmp/my_data.csv", options) { |row| puts row }
CSV::MalformedCSVError: Illegal quoting in line 1.
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1925:in `block (2 levels) in shift'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1887:in `each'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1887:in `block in shift'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1849:in `loop'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1849:in `shift'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1791:in `each'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1208:in `block in foreach'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1354:in `open'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1207:in `foreach'
from (irb):22
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/bin/irb:16:in `<main>'
Ensuite, j'ai essayé de simplifier les données, c'est-à-dire.
"name","age","email"
"jignesh","30","[email protected]"
cependant, je reçois toujours la même erreur:
1.9.3dev :023 > CSV.foreach("/tmp/my_data.csv", options) { |row| puts row }
CSV::MalformedCSVError: Illegal quoting in line 1.
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1925:in `block (2 levels) in shift'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1887:in `each'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1887:in `block in shift'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1849:in `loop'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1849:in `shift'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1791:in `each'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1208:in `block in foreach'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1354:in `open'
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/lib/Ruby/1.9.1/csv.rb:1207:in `foreach'
from (irb):23
from /home/jigneshgohel/.rvm/rubies/Ruby-1.9.3-rc1/bin/irb:16:in `<main>'
Encore une fois j'ai essayé de simplifier les données comme ceci:
name,age,email
jignesh,30,[email protected]
et ça marche.Voir le résultat ci-dessous:
1.9.3dev :024 > CSV.foreach("/tmp/my_data.csv") { |row| puts row }
name
age
email
jignesh
30
[email protected]
=> nil
Mais je vais recevoir les fichiers CSV contenant des données de citations. Supprimer la solution de citations n’est donc pas ce que je cherche. Je ne peux pas comprendre la cause de l’erreur: CSV :: MalformedCSVError: Citations illégales à la ligne 1. dans mes exemples précédents.
J'ai vérifié qu'il n'y avait pas d'espaces de début/fin dans le fichier CSV en activant les options "Afficher les caractères d'espacement" et "Afficher les fins de ligne" dans mon éditeur de texte. J'ai également vérifié le codage à l'aide de l'option suivante.
1.9.3dev :026 > File.open("/tmp/my_data.csv").read.encoding
=> #<Encoding:UTF-8>
_ {Remarque: j'ai essayé d'utiliser CSV.read aussi mais la même erreur avec cette méthode.
Quelqu'un peut-il m'aider à sortir de ce problème et à me faire comprendre où il ne va pas?
======================
Je viens de trouver le post suivant à: http://www.Ruby-forum.com/topic/448070 et j'ai essayé de suivre:
file_data = file.read
file_data.gsub!('"', "'")
arr_of_arrs = CSV.parse(file_data)
arr_of_arrs.each do |arr|
Rails.logger.debug "=======#{arr}"
end
et a obtenu la sortie suivante:
=======["\xEF\xBB\xBF'date/time'", "'settlement id'", "'type'", "'order id'", "'sku'", "'description'", "'quantity'", "'marketplace'", "'fulfillment'", "'order city'", "'order state'", "'order postal'", "'product sales'", "'shipping credits'", "'gift wrap credits'", "'promotional rebates'", "'sales tax collected'", "'selling fees'", "'fba fees'", "'other transaction fees'", "'other'", "'total'"]
=======["'Mar 1", " 2013 12:03:54 AM PST'", "'5481545091'", "'Order'", "'108-0938567-7009852'", "'ALS2GL36LED'", "'Solar Two Directional 36 Bright White LED Security Flood Light with Motion Activated Sensor'", "'1'", "'Amazon.com'", "'Amazon'", "'Pasadena'", "'CA'", "'91104-1056'", "'43.00'", "'3.25'", "'0'", "'-3.25'", "'0'", "'-6.45'", "'-3.75'", "'0'", "'0'", "'32.80'"]
qui a gâché la lecture correcte des données car le col_sep par défaut utilisé est une virgule . Cependant, j’ai essayé d’utiliser l’option quote_char comme ceci:
arr_of_arrs = CSV.parse(file_data, :quote_char => "'")
mais cela a fini par l'erreur suivante:
CSV::MalformedCSVError (Illegal quoting in line 1.):
Merci, Jignesh
quote_chars = %w(" | ~ ^ & *)
begin
@report = CSV.read(csv_file, headers: :first_row, quote_char: quote_chars.shift)
rescue CSV::MalformedCSVError
quote_chars.empty? ? raise : retry
end
ce n'est pas parfait mais cela fonctionne la plupart du temps.
N.B. CSV.parse
prend les mêmes paramètres que CSV.read
, de sorte qu'un fichier ou des données de la mémoire peuvent être utilisés
Merci pour la suggestion d'encodage. Cela a résolu le problème des citations illégales pour moi.
Remarque: Si vous souhaitez que l'itérateur ignore la ligne d'en-tête, ajoutez headers: :first_row
, comme suit:
CSV.foreach("test.csv", encoding: "bom|utf-8", headers: :first_row)
Je viens d'avoir un problème comme celui-ci et j'ai découvert que CSV n'aime pas les espaces entre les caractères col-sep et quote. Une fois que j'ai enlevé ceux-ci tout s'est bien passé . Donc j'avais:
12, "N", 12, "Pacific/Majuro"
mais une fois que j'ai gsubed les espaces en utilisant
.gsub(/,\s+\"/,',\"')
résultant en
12,"N", 12,"Pacific/Majuro"
tout s'est bien passé.
J'ai essayé de lire le fichier et d'obtenir une chaîne, puis d'analyser le processus dans une table CSV, mais j'ai reçu une exception:
CSV.read(File.read('file.csv'), headers: true)
CSV::MalformedCSVError: Unclosed quoted field on line 1794.
Aucune des réponses fournies ici n'a fonctionné pour moi. En fait, celui qui a obtenu le plus grand nombre de votes prenait tellement de temps à analyser que j'ai finalement mis fin à l'exécution. Cela a probablement généré de nombreuses exceptions et ce temps est coûteux pour un fichier volumineux.
Encore plus problématique, l’erreur n’est pas très utile, car c’est un gros fichier CSV. Où se trouve exactement la ligne 1794? J'ai ouvert le fichier dans LibreOffice qui s'est ouvert sans aucun problème. La ligne 1794 était la dernière ligne de données du fichier csv. Donc, apparemment, le problème concernait la fin du fichier CSV. J'ai décidé d'inspecter le contenu sous forme de chaîne avec File.read. J'ai remarqué que la chaîne se terminait par un caractère de retour chariot:
,\"\"\r
J'ai décidé d'utiliser chomp et de supprimer le retour chariot à la fin du fichier. Notez que si $/n'a pas été modifié par rapport au séparateur d'enregistrement Ruby par défaut, chomp supprime également les caractères de retour chariot (c'est-à-dire qu'il supprimera\n,\r et\r\n).
CSV.parse(File.read('file.csv' ).chomp, headers: true)
=> #<CSV::Table mode:col_or_row row_count:1794>
Et ça a fonctionné. Le problème était le caractère\r à la fin du fichier.