2009-02-12 8 views
29

Je consomme un flux de données qui a récemment ajouté un en-tête de nomenclature Unicode (U + FEFF), et ma tâche de rake est maintenant foirée.Comment éviter de trébucher sur la nomenclature UTF-8 lors de la lecture de fichiers

Je peux ignorer les 3 premiers octets avec file.gets[3..-1] mais y a-t-il une façon plus élégante de lire les fichiers dans Ruby qui peuvent gérer cela correctement, que la nomenclature soit présente ou non?

+2

C'est une nomenclature Unicode qui n'est pas une nomenclature UTF-8. – AnthonyWJones

+0

Merci, je viens de le réaliser. C'est en fait 3 octets, pas un ... J'ai édité la question pour en dire autant. –

Répondre

48

Avec Ruby 1.9.2, vous pouvez utiliser le mode r:bom|utf-8

text_without_bom = nil #define the variable outside the block to keep the data 
File.open('file.txt', "r:bom|utf-8"){|file| 
    text_without_bom = file.read 
} 

ou

text_without_bom = File.read('file.txt', encoding: 'bom|utf-8') 

ou

text_without_bom = File.read('file.txt', mode: 'r:bom|utf-8') 

Peu importe, si la nomenclature est disponible en le fichier ou non.


Vous pouvez également utiliser l'option d'encodage avec d'autres commandes:

text_without_bom = File.readlines(@filename, "r:utf-8") 

(Vous obtenez un tableau avec toutes les lignes).

Ou avec CSV:

require 'csv' 
CSV.open(@filename, 'r:bom|utf-8'){|csv| 
    csv.each{ |row| p row } 
} 
+0

Existe-t-il un moyen de le faire avec des fichiers CSV utilisant la bibliothèque CSV intégrée dans ruby? J'ai essayé de passer ': encoding =>" r: bom | utf-8 "' à foreach de CSV mais il lit toujours la nomenclature comme si elle faisait partie de la première colonne de l'en-tête. – Aaron

+2

Je pense que c'est possible. Avec 'CVS.read (filename,: encoding => 'utf-8')' vous pouvez définir le codage avec CSV (ou est-ce 'CSV.load'?). Je pense que ce shold est aussi possible avec le bom-logic: ': encoding => 'bom | utf-8')'. Je ne peux pas le tester moi-même - désolé. – knut

+0

Ce qui suit a fonctionné pour moi: 'fichier = File.open (@filename, 'r: bom | utf-8')' 'csv = CSV.new (fichier, faster_csv_options)' 'csv.each do | row | ' ' ... ' ' file.close' – Aaron

10

Je ne voudrais pas ignorer aveuglément les trois premiers octets; Que faire si le producteur arrête en ajoutant à nouveau la nomenclature? Ce que vous devez faire est examiner les premiers octets, et si elles sont 0xEF 0xBB 0xBF, les ignorer. C'est la forme que prend le caractère BOM (U + FEFF) en UTF-8; Je préfère traiter cela avant d'essayer de décoder le flux, car la gestion de la nomenclature est tellement incohérente d'un langage/outil/cadre à l'autre.

En fait, c'est ainsi que vous êtes supposé pour faire face à une nomenclature. Si un fichier a été traité en UTF-16, vous devez examiner les deux premiers octets avant de commencer le décodage afin de savoir si vous voulez le lire en big-endian ou en little-endian. Bien sûr, la nomenclature UTF-8 n'a rien à voir avec l'ordre des octets, elle est juste là pour vous faire savoir que l'encodage est UTF-8, au cas où vous ne le saviez pas déjà.

0

Je ne serais pas « confiance » certains fichiers à coder en UTF-8 quand une nomenclature de 0xEF 0xBB 0xBF est présent, vous pouvez échouer. Habituellement, lors de la détection de la nomenclature UTF-8, il devrait s'agir d'un fichier encodé en UTF-8 bien sûr. Mais, si par exemple quelqu'un vient d'ajouter la nomenclature UTF-8 à un fichier ISO, vous ne réussirez pas à encoder un tel fichier s'il y a des octets au-dessus de 0x0F. Vous pouvez faire confiance au fichier si vous avez seulement des octets jusqu'à 0x0F à l'intérieur, car dans ce cas, c'est un fichier ASCII compatible UTF-8 et en même temps c'est un fichier UTF-8 valide.

S'il n'y a pas seulement des octets < = 0x0F dans le fichier (après la nomenclature), pour être sûr que le codage UTF-8 est correct, vous devrez vérifier les séquences valides et - même si toutes les séquences sont valides - vérifiez également si chaque point de code d'une séquence utilise la séquence la plus courte possible et vérifiez également s'il n'y a pas de code correspondant à un substitut faible ou élevé. Vérifiez également si les octets maximum d'une séquence ne sont pas plus de 4 et le plus haut point de code est 0x10FFFF. Le point de code le plus élevé limite également les bits de charge utile de startbyte à ne pas être supérieur à 0x4 et la charge utile du premier octet suivant pas supérieure à 0xF. Si tous les contrôles mentionnés passent avec succès, votre nomenclature UTF-8 dit la vérité.