ruby - rails encoding utf 8
Ruby lee el archivo CSV como UTF-8 y/o convierte la codificación ASCII-8Bit a UTF-8 (3)
Estoy usando ruby 1.9.2
Estoy tratando de analizar un archivo CSV que contiene algunas palabras en francés (por ejemplo spécifié) y colocar el contenido en una base de datos MySQL.
Cuando leo las líneas del archivo CSV,
file_contents = CSV.read("csvfile.csv", col_sep: "$")
Los elementos regresan como cadenas codificadas en ASCII-8BIT (spécifié se convierte en sp / xE9cifi / xE9), y las cadenas como "spécifié" NO se guardan correctamente en mi base de datos MySQL.
Yehuda Katz dice que ASCII-8BIT es realmente información "binaria", lo que significa que CSV no tiene idea de cómo leer la codificación adecuada.
Entonces, si trato de hacer que CSV fuerce la codificación de esta manera:
file_contents = CSV.read("csvfile.csv", col_sep: "$", encoding: "UTF-8")
Obtuve el siguiente error
ArgumentError: invalid byte sequence in UTF-8:
Si vuelvo a mis Cadenas codificadas en ASCII-8BIT originales y examino la Cadena que mi CSV lee como ASCII-8BIT, se ve como "No sp / xE9cifi / xE9" en lugar de "Non spécifié".
No puedo convertir "Non sp / xE9cifi / xE9" a "Non spécifié" haciendo esto "Non sp/xE9cifi/xE9".encode("UTF-8")
porque me sale este error:
Encoding::UndefinedConversionError: "/xE9" from ASCII-8BIT to UTF-8
,
lo que Katz indicó que sucedería porque ASCII-8BIT no es realmente una "codificación" de cadenas adecuada.
Preguntas:
- ¿Puedo hacer que CSV lea mi archivo con la codificación adecuada? ¿Si es así, cómo?
- ¿Cómo convierto una cadena ASCII-8BIT a UTF-8 para un almacenamiento adecuado en MySQL?
Con ruby> = 1.9 puedes usar
file_contents = CSV.read("csvfile.csv", col_sep: "$", encoding: "ISO8859-1:utf-8")
El ISO8859-1:utf-8
significa: el archivo csv está codificado con ISO8859-1, pero convierte el contenido a utf-8
Si prefiere un código más detallado, puede usar:
file_contents = CSV.read("csvfile.csv", col_sep: "$",
external_encoding: "ISO8859-1",
internal_encoding: "utf-8"
)
He estado lidiando con este problema por un tiempo y ninguna de las otras soluciones funcionó para mí.
Lo que hizo el truco fue almacenar la cadena conflictiva en un archivo binario , luego leer el archivo normalmente y usar esta cadena para alimentar el módulo 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)
deceze♦ tiene razón, ese es el texto codificado ISO8859-1 (AKA Latin-1). Prueba esto:
file_contents = CSV.read("csvfile.csv", col_sep: "$", encoding: "ISO8859-1")
Y si eso no funciona, puede usar Iconv
para arreglar las cadenas individuales con algo como esto:
require ''iconv''
utf8_string = Iconv.iconv(''utf-8'', ''iso8859-1'', latin1_string).first
Si latin1_string
es "Non sp/xE9cifi/xE9"
, entonces utf8_string
será "Non spécifié"
. Además, Iconv.iconv
puede desmantelar matrices enteras a la vez:
utf8_strings = Iconv.iconv(''utf-8'', ''iso8859-1'', *latin1_strings)
Con Rubies más nuevos, puedes hacer cosas como esta:
utf8_string = latin1_string.force_encoding(''iso-8859-1'').encode(''utf-8'')
donde latin1_string
cree que está en ASCII-8BIT pero está realmente en ISO-8859-1.