cuando importamos datos csv, ¿cómo eliminar " secuencia de bytes inválida en UTF-8"


Permitimos a los usuarios importar datos a través de csv (usando ruby 1.9.2, por lo tanto es fastercsv).

Al ser datos de usuario, por supuesto, puede que no se desinfecten correctamente.

Cuando intentamos mostrar los datos en un método / index a veces obtenemos el error "secuencia de bytes inválida en UTF-8" apuntando a nuestro erb donde mostramos uno de los campos widget.name

Cuando hacemos la importación nos gustaría FORZAR que los datos entrantes sean válidos... ¿hay un operador ruby que mapeará una cadena a una cadena válida cadena utf8, por ejemplo, algo como

goodstring = badstring.no_more_invalid_bytes

Un ejemplo de datos 'malos' es char que parece un guion pero no es un guion ascii regular. Preferiríamos asignar los caracteres no utf-8 a un equivalente ascii razonable (umlat-u va a u para exmaple), PERO estamos de acuerdo con simplemente quitar el carácter a.

Dado que esto es cuando se importan muchos datos, debe ser un operador integrado rápido, con suerte...


Nota: aquí hay un ejemplo de los datos. El archivo viene de windows y es ascii de 8 bits. cuando lo importamos y en nuestro erb mostramos widget. name. inspect (en lugar de widget.name) obtenemos: "Cadenas \ x96 Accesorios"

Así que un ejemplo de los datos es un "guion" que en realidad es código de 8 bits 96.

- - - cuando cambiamos nuestro análisis csv para asignar fldval = d. encode ('UTF-8') arroja este error:

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

Lo que estamos buscando es una manera simple de forzarlo a ser válido utf8 independientemente del tipo de origen, incluso si simplemente lo despojamos no ascii.


Aunque no es tan 'agradable' como forzar la codificación, esto funciona a un ligero costo para nuestro tiempo de importación: d. to_s. strip. gsub (/\P{ASCII}/,") Gracias, Mladen!

 57
Author: jpwynn, 2011-02-19

8 answers

Ruby 1.9 CSV tiene un nuevo analizador que funciona con m17n. El analizador funciona con la codificación del objeto IO en la cadena. Los siguientes métodos: ::foreach, ::open, ::read, and ::readlines podría tomar opciones opcionales :encoding que podría especificar la Codificación.

Por ejemplo:

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

Convertiría todas las cadenas a UTF-8.

También puede usar el nombre de codificación más estándar 'ISO-8859-1'

CSV.read('/..', {:headers => true, :col_sep => ';', :encoding => 'ISO-8859-1'})
 113
Author: Trung Lê,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-05 12:37:02

Respondí a una pregunta similar que trata sobre la lectura de archivos externos en 1.9.2 con codificaciones no UTF-8. Creo que esa respuesta te ayudará mucho: Problema de codificación de caracteres en Rails v3 / Ruby 1.9.2

Tenga en cuenta que necesita conocer la codificación de origen para convertirlo de forma fiable. Hay bibliotecas como la que enlacé en mi otra respuesta que pueden ayudarte a determinar esto.

Además, si no está cargando los datos de un archivo, puede convertir la codificación de una cadena en 1.9.2 con bastante facilidad:

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

Sin embargo, es raro que esté construyendo una cadena en otra codificación, y es mejor convertirla en el momento en que se lee en su entorno si es posible.

 13
Author: coreyward,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:50

Ruby 1.9 puede cambiar la codificación de cadenas con detección y reemplazo no válidos:

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

Para cadenas inusuales como cadenas cargadas desde un archivo de codificación desconocida, es aconsejable usar #encode en lugar de una expresión regular, #gsub o #delete, porque todas necesitan que la cadena se analice-- pero si la cadena está rota, no se puede analizar, por lo que esos métodos fallan.

Si recibes un mensaje como este:

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

Entonces probablemente esté tratando de convertir una cadena binaria que ya está en UTF-8, y puedes forzar UTF-8:

str.force_encoding('UTF-8')

Si sabe que la cadena original no está en UTF-8 binario, o si la cadena de salida tiene caracteres ilegales, lea las transliteraciones de codificación Ruby.

 7
Author: joelparkerhenderson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-19 16:09:15
CSV.parse(File.read('/path/to/csv').scrub)
 7
Author: Bill Lipa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-25 15:22:21

Si está utilizando Rails , puede intentar arreglarlo con lo siguiente

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

Elimina los caracteres utf-8 no válidos y los reemplaza con caracteres válidos. Más información: https://apidock.com/rails/String/mb_chars

 4
Author: dom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-09 09:56:38

Cargue el archivo CSV en la hoja de cálculo de Google Docs y vuelva a descargarlo como archivo CSV. Importación y voila! (Trabajó en mi caso)

Probablemente Google lo convierte al formato deseado..

Fuente: Excel a CSV con codificación UTF-8

 1
Author: Jonathan Lin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:32

Solo haz esto

anyobject.to_csv(:encoding => 'utf-8')
 0
Author: Daniel Antonio Nuñez Carhuayo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-26 16:27:21

Como ha mencionado alguien más, scrub funciona bien para limpiar esto en Ruby 2.1+. Si tiene un archivo grande puede que no desee leer todo en memoria, por lo que puede usar scrub como este:

data = IO::read(file_path).scrub("")
CSV.parse(data, :col_sep => ',', :headers => true)  do |row|
   puts row
end
 0
Author: Andy Fraley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-16 20:39:31