web-dev-qa-db-fra.com

lorsque nous importons des données csv, comment éliminer les "séquences d'octets invalides en UTF-8"

nous permettons aux utilisateurs d'importer des données via csv (en utilisant Ruby 1.9.2, donc c'est plus rapidecsv).

étant des données utilisateur, bien sûr, elles pourraient ne pas être correctement nettoyées.

Lorsque nous essayons d'afficher les données dans une méthode/index, nous obtenons parfois l'erreur "séquence d'octets invalide en UTF-8" pointant vers notre erb où nous affichons l'un des champs widget.name

Lorsque nous faisons l'importation, nous aimerions forcer les données entrantes à être valides ... y a-t-il un opérateur Ruby qui mappera une chaîne à une chaîne utf8 valide, par exemple, quelque chose comme

goodstring = badstring.no_more_invalid_bytes

Un exemple de "mauvaises" données est le caractère qui ressemble à un trait d'union mais qui n'est pas un trait d'union ascii normal. Nous préférons mapper les caractères non-utf-8 à un équivalent ascii raisonnable (umlat-u devenant u pour exmaple) MAIS nous sommes d'accord pour simplement supprimer le caractère.

puisque c'est lors de l'importation de beaucoup de données, il doit être un opérateur intégré rapide, je l'espère ...


Remarque: voici un exemple des données. Le fichier vient de Windows et est en 8 bits ascii. lorsque nous l'importons et dans notre erb nous affichons widget.name.inspect (au lieu de widget.name) nous obtenons: "Chains\x96 Accessories"

donc un exemple des données est un "tiret" qui est en fait le code 8 bits 96.

--- lorsque nous avons modifié notre analyse csv pour attribuer fldval = d.encode ('UTF-8'), il renvoie cette erreur:

Encoding::UndefinedConversionError in StoresController#importfinderitems
"\x96" from ASCII-8BIT to UTF-8

ce que nous recherchons est un moyen simple de le forcer à être valide utf8 quel que soit le type d'origine, même si nous supprimons simplement les non-ascii.


bien qu'il ne soit pas aussi agréable que de forcer l'encodage, cela fonctionne à un léger coût pour notre temps d'importation: d.to_s.strip.gsub (/\P {ASCII} /, '') Merci, Mladen!

59
jpwynn

Ruby 1.9 CSV a un nouvel analyseur qui fonctionne avec m17n. L'analyseur fonctionne avec l'encodage de IO objet dans la chaîne. Méthodes suivantes: ::foreach, ::open, ::read, and ::readlines pourrait prendre des options facultatives :encoding dont vous pouvez spécifier l'encodage.

Par exemple:

CSV.read('/path/to/file', :encoding => 'windows-1251:utf-8')

Convertirait toutes les chaînes en UTF-8.

Vous pouvez également utiliser le nom d'encodage plus standard "ISO-8859-1"

CSV.read('/..', {:headers => true, :col_sep => ';', :encoding => 'ISO-8859-1'})
121
Trung Lê

J'ai répondu à une question similaire qui traite de la lecture de fichiers externes dans 1.9.2 avec des encodages non UTF-8. Je pense que cette réponse vous aidera beaucoup: problème d'encodage de caractères dans Rails v3/Ruby 1.9.2

Notez que vous devez connaître le codage source pour que vous puissiez le convertir de manière fiable. Il y a des bibliothèques comme celle à laquelle j'ai lié dans mon autre réponse qui peuvent vous aider à déterminer cela.

De plus, si vous ne chargez pas les données d'un fichier, vous pouvez convertir l'encodage d'une chaîne en 1.9.2 assez facilement:

'string'.encode('UTF-8')

Cependant, il est rare que vous construisiez une chaîne dans un autre encodage, et il est préférable de la convertir au moment où elle est lue dans votre environnement si possible.

13
coreyward
CSV.parse(File.read('/path/to/csv').scrub)
10
Bill Lipa

Ruby 1.9 peut changer l'encodage des chaînes avec une détection et un remplacement invalides:

str = str.encode('UTF-8', :invalid => :replace)

Pour les chaînes inhabituelles telles que les chaînes chargées à partir d'un fichier d'encodage inconnu, il est judicieux d'utiliser #encode au lieu d'une expression régulière, #gsub ou #delete, car elles ont toutes besoin d'analyser la chaîne - mais si la chaîne est cassée, il ne peut pas être analysé, donc ces méthodes échouent.

Si vous recevez un message comme celui-ci:

error ** from ASCII-8BIT to UTF-8

Ensuite, vous essayez probablement de convertir une chaîne binaire qui est déjà en UTF-8, et vous pouvez forcer UTF-8:

str.force_encoding('UTF-8')

Si vous savez que la chaîne d'origine n'est pas en UTF-8 binaire, ou si la chaîne de sortie a des caractères illicites, alors lisez la suite sur Ruby encoding translittérations.

7
joelparkerhenderson

Si vous utilisez Rails , vous pouvez essayer de le réparer avec les éléments suivants

'Your string with strange stuff #@~'.mb_chars.tidy_bytes

Il vous supprime les caractères utf-8 invalides et les remplace par des caractères valides. Plus d'informations: https://apidock.com/Rails/String/mb_chars

4
dom

Importez le fichier CSV dans la feuille de calcul Google Docs et téléchargez-le à nouveau en tant que fichier CSV. Importez et le tour est joué! (A travaillé dans mon cas)

Vraisemblablement, Google le convertit au format souhaité.

Source: Excel vers CSV avec encodage UTF-8

1
Jonathan Lin

Ne faites que ça

anyobject.to_csv(:encoding => 'utf-8')

Comme mentionné par quelqu'un d'autre, scrub fonctionne bien pour le nettoyer dans Ruby 2.1+. Si vous avez un gros fichier, vous ne voudrez peut-être pas lire le tout en mémoire, vous pouvez donc utiliser scrub comme ça:

data = IO::read(file_path).scrub("")
CSV.parse(data, :col_sep => ',', :headers => true)  do |row|
   puts row
end
0
Andy Fraley