6
votes

Ruby CSV BOM | encodage UTF-8 pour StringIO

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!


2 commentaires

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.


3 Réponses :


2
votes

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


0 commentaires

2
votes

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.


0 commentaires

2
votes

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


0 commentaires