Ruby 2.6.3.
J'ai essayé d'analyser un objet StringIO
dans une instance CSV
avec le codage bom|utf-8
, afin que le caractère BOM (indésirable) soit supprimé et que le contenu soit codé en UTF-8:
require 'csv' CSV_READ_OPTIONS = { headers: true, encoding: 'bom|utf-8' }.freeze # File content is: "\xEF\xBB\xBFid\n12" first_row = CSV.read('bom_content.csv', CSV_READ_OPTIONS).first first_row.headers.first.include?("\xEF\xBB\xBF") # This returns false
Apparemment, l'encodage bom|utf-8
ne fonctionne pas pour les objets StringIO
, mais j'ai trouvé qu'il fonctionne pour les fichiers, par exemple:
require 'csv' CSV_READ_OPTIONS = { headers: true, encoding: 'bom|utf-8' }.freeze content = StringIO.new("\xEF\xBB\xBFid\n123") first_row = CSV.parse(content, CSV_READ_OPTIONS).first first_row.headers.first.include?("\xEF\xBB\xBF") # This returns true
Étant donné que je dois travailler directement avec StringIO
, pourquoi CSV
ignore bom|utf-8
encodage bom|utf-8
? Existe-t-il un moyen de supprimer le caractère BOM de l'instance StringIO
?
Merci!
3 Réponses :
Ruby n'aime pas les nomenclatures. Il ne les gère que lors de la lecture d'un fichier , jamais ailleurs, et même dans ce cas, il ne les lit que pour pouvoir s'en débarrasser. Si vous voulez une nomenclature pour votre chaîne ou une nomenclature lors de l'écriture d'un fichier, vous devez la gérer manuellement.
Il y a probablement des gemmes pour faire cela, même si c'est facile à faire soi-même
if string[0...3] == "\xef\xbb\xbf" string = string[3..-1].force_encoding('UTF-8') elsif string[0...2] == "\xff\xfe" string = string[2..-1].force_encoding('UTF-16LE') # etc
J'ai découvert que forcer le codage à utf8 sur la string
StringIO et supprimer la nomenclature pour générer un nouveau StringIO fonctionnait:
require 'csv' CSV_READ_OPTIONS = { headers: true}.freeze content = StringIO.new("\xEF\xBB\xBFid\n123") csv_file = StringIO.new(content.string.force_encoding('utf-8').sub("\xEF\xBB\xBF", '')) first_row = CSV.parse(csv_file, CSV_READ_OPTIONS).first first_row.headers.first.include?("\xEF\xBB\xBF") # => false
L'option d' encoding
n'est plus nécessaire. Ce n'est peut-être pas la meilleure option en termes de mémoire, mais cela fonctionne.
Ruby 2.7 a ajouté la méthode set_encoding_by_bom
à IO
. Cette méthode utilise la marque d'ordre des octets et définit le codage.
require 'csv' require 'stringio' CSV_READ_OPTIONS = { headers: true }.freeze content = StringIO.new("\xEF\xBB\xBFid\n123") content.set_encoding_by_bom first_row = CSV.parse(content, CSV_READ_OPTIONS).first first_row.headers.first.include?("\xEF\xBB\xBF") #=> false
N'est-il pas possible de supprimer la nomenclature avant de créer l'instance StringIO ou d'en créer une autre basée sur une chaîne UTF-8 sans nomenclature? Toutes les versions de StringIO publiées ne prennent pas en charge la gestion des nomenclatures.
Le problème est que (depuis Ruby 2.4) la nomenclature est une propriété de fichiers , pas un encodage. Si vous disposez déjà d'une chaîne codée, la nomenclature n'existe pas, car les caractères ont déjà été correctement lus conformément à la nomenclature et elle n'est plus nécessaire. Puisque StringIO est soutenu par une chaîne - pas un fichier - il ne comprend pas non plus la nomenclature.