Ruby lit le fichier CSV comme UTF-8 et / ou convertit ASCII-8Bit encoding en UTF-8

j'utilise ruby 1.9.2

je suis en train de parse un fichier CSV qui contient quelques mots en français (p. ex. spécifié) et placer le contenu dans une base de données MySQL.

quand je lis les lignes du fichier CSV,

file_contents = CSV.read("csvfile.csv", col_sep: "$")

les éléments reviennent comme des cordes qui sont ASCII-8BIT encodées( spécifié devient spxE9cifixE9), et les cordes comme "spécifié" ne sont donc pas correctement enregistré dans ma base de données MySQL.

Yehuda Katz dit que ASCII-8BIT est vraiment des données "binaires" ce qui signifie que CSV n'a aucune idée de la façon de lire l'encodage approprié.

donc, si j'essaie de faire CSV force l'encodage comme ceci:

file_contents = CSV.read("csvfile.csv", col_sep: "$", encoding: "UTF-8")

j'obtiens l'erreur suivante

ArgumentError: invalid byte sequence in UTF-8: 

si je retourne à mes chaînes codées ASCII-8BIT originales et que j'examine la chaîne que mon CSV lit comme ASCII-8BIT, il ressemble à ce " Non spxE9cifixE9 "au lieu de"Non spécialisé".

je ne peux pas convertir "Non spxE9cifixE9" à "Non spécifié" en faisant cela "Non spxE9cifixE9".encode("UTF-8")

parce que j'ai cette erreur:

Encoding::UndefinedConversionError: "xE9" from ASCII-8BIT to UTF-8 ,

, ce qui, selon Katz, se produirait parce que ASCII-8BIT n'est pas vraiment une chaîne de caractères appropriée"encoding".

Questions:

  1. puis-je obtenir CSV pour lire mon fichier dans le codage approprié? Si oui, comment?
  2. comment convertir une chaîne ASCII-8BIT en UTF-8 pour un stockage approprié dans MySQL?
49
demandé sur jpemberthy 2011-08-13 05:27:21

3 réponses

deceze est à droite, c'est-ISO8859-1 (ALIAS Latin-1) le texte codé. Essayez ceci:

file_contents = CSV.read("csvfile.csv", col_sep: "$", encoding: "ISO8859-1")

et si cela ne fonctionne pas, vous pouvez utiliser Iconv pour fixer les cordes individuelles avec quelque chose comme ceci:

require 'iconv'
utf8_string = Iconv.iconv('utf-8', 'iso8859-1', latin1_string).first

si latin1_string est "Non sp\xE9cifi\xE9" , alors utf8_string sera "Non spécifié" . En outre, Iconv.iconv peut démonter des tableaux entiers à la fois:

utf8_strings = Iconv.iconv('utf-8', 'iso8859-1', *latin1_strings)

avec de nouveaux Rubis, vous pouvez faire des choses comme ceci:

utf8_string = latin1_string.force_encoding('iso-8859-1').encode('utf-8')

latin1_string pense qu'il est en ASCII-8BIT mais est vraiment EN ISO-8859-1.

53
répondu mu is too short 2017-05-23 12:10:54

avec ruby > = 1.9 vous pouvez utiliser

file_contents = CSV.read("csvfile.csv", col_sep: "$", encoding: "ISO8859-1:utf-8")

le ISO8859-1:utf-8 signifie: le fichier csv est codé ISO8859-1, mais convertir le contenu en utf-8

si vous préférez un code plus verbeux, vous pouvez utiliser:

file_contents = CSV.read("csvfile.csv", col_sep: "$", 
    external_encoding: "ISO8859-1", 
    internal_encoding: "utf-8"
  )
22
répondu knut 2015-11-20 19:15:25

Je m'occupe de cette question depuis un certain temps et aucune des autres solutions n'a fonctionné pour moi.

la chose qui a fait l'astuce était de stocker le conflit chaîne de caractères dans un fichier binaire , puis lire le fichier normalement et en utilisant cette chaîne de caractères pour alimenter le module CSV:

tempfile = Tempfile.new("conflictive_string")
tempfile.binmode
tempfile.write(conflictive_string)
tempfile.close
cleaned_string = File.read(tempfile.path)
File.delete(tempfile.path)
csv = CSV.new(cleaned_string)
1
répondu fguillen 2015-11-20 16:03:39