2012-05-18 17 views
7

Uso una aplicación de iPhone que me envía un correo electrónico periódicamente en formato CSV. Tengo un script de ruby ​​que resume los datos en ese registro con registros más antiguos. Recientemente, el desarrollador de la aplicación lanzó una actualización que, por algún motivo desconocido, agregó un retorno de carro al final de cada línea, lo que provocó el error de mi secuencia de comandos. De acuerdo con los documentos, :row_end de forma predeterminada debería ser :auto, que debería aceptar \r\n o \n (en 1.9.2). He intentado usar Ruby 1.8.7, 1.9.2 y FasterCSV con 1.8.7. Consigo varios mensajes de error con estos diferentes intentos, incluyendoRuby CSV no comprende r n como fila final

  • CSV::IllegalFormatError
  • campos Unquoted no permiten \r o \n (línea 1) (FasterCSV::MalformedCSVError)
  • no puede dup NilClass (TypeError)

en 1.9.2. (El \r no se encuentra en un campo, que es el final de la línea!) Los datos que antes era la siguiente:

03-12-2012 07:59,120.0, 
03-11-2012 08:27,120.0, 
03-10-2012 07:57,120.0, 

Ahora parece que esto:

03-12-2012 07:59,120.0,^M 
03-11-2012 08:27,120.0,^M 
03-10-2012 07:57,120.0,^M 

Pensando que CSV puede estar pensando la ^M es en el último campo, he intentado añadir otro coma:

03-12-2012 07:59,120.0,,^M 

en vano.

Lo único que puedo imaginar es que CSV requiere que todos los campos estén entre comillas dobles? Puedo pensar en varias soluciones, como leer primero el archivo, masticar los extremos y luego procesar la matriz con CSV, pero primero quiero saber qué estoy haciendo mal. Parece que debería funcionar.

Por cierto mi código es simplemente:

CSV.foreach(File.join($import_dir, file)) do |record| 

y He tratado de establecer :row_end => "\r\n" en vano.

Estoy en Mac OS X 10.6.8.

Respuesta

3

funciona para mí en 1.9.3:

[email protected]:~$ irb 
1.9.3p0 :001 > require 'csv' 
=> true 
1.9.3p0 :002 > CSV.foreach("rn.csv") do |row| 
1.9.3p0 :003 > p row 
1.9.3p0 :004 > end 
["1","2","3","4","5"] 
["6","7","8","9","10"] 

y el archivo tiene de hecho retornos de carro en ella:

[email protected]:~$ od -a rn.csv 
0000000 1 , 2 , 3 , 4 , 5 cr nl 6 , 7 , 8 
0000020 , 9 , 1 0 cr nl 
0000027 
+2

Gracias por el consejo. No había pensado en mirar el archivo con od. Resulta que la línea termina en \ r \ r \ n. – chetstone

3

Ha mencionado intentar :row_end => '\r\n'. Las comillas simples tratan (la mayoría de las instancias de) barras diagonales inversas como barras diagonales regulares; intente :row_end => "\r\n", con comillas dobles.

+0

Mi error. Lo intenté. El mismo problema. – chetstone

5

Intente configurar la row_end a

"\r\n" 

Esto es diferente a '\ r \ n': cadenas entre comillas sencillas sólo le permiten escapar 'y \, cualquier otra cosa es tratado como un \ literal, es decir,

'\r' == "\\r" 

es cierto

+0

Lo siento, olvidé mencionar que lo intenté también. – chetstone

2

Las líneas del archivo en realidad terminan con \ r \ r \ n, no \ r \ n Este es embarazoso, debería haber revisado el archivo con más detalle. I asumía que el final de la línea era \ n, ya que estoy en una caja de Unix. Pero cuando Emacs abrió el archivo, entró automáticamente en modo "DOS", por lo que \ r \ n apareció como una nueva línea y solo mostró el \ r \ n como "^ M"

+0

Este fue el caso para mí. Vim mostró el '' extra' como '^ M' y las líneas realmente terminaron en' \ r \ r \ n'. Cuidado con la gente – ElDog

6

Porque CSV necesita leer/analizar el todo el archivo cuando row_end es automático, tuve que hacer lo siguiente para evitar el formato y la codificación de excepciones.

  • decodificar el archivo a través de File.read
  • quitar esos retornos de carro molestos (podría ser uno o más)
  • analizar el archivo limpiado como CSV
file = File.read(temp_file.path, encoding: 'ISO-8859-1:UTF-8') 
file = file.tr("\r", '') 

CSV.parse(file, headers: true) do |row| 
    # do all the things 
end 

Nota: Estoy usando la versión Ruby 2.1.3 para una aplicación de Rails 4.

Cuestiones relacionadas