2009-02-12 13 views
29

Estoy consumiendo una fuente de datos que recientemente ha agregado un encabezado de lista de materiales Unicode (U + FEFF), y mi tarea de rastrillar ahora está en mal estado.Cómo evitar tropezar con BOM UTF-8 al leer archivos

Puedo omitir los primeros 3 bytes con file.gets[3..-1], pero ¿hay una forma más elegante de leer archivos en Ruby que puedan manejar esto correctamente, ya sea que haya una lista de materiales presente o no?

+2

Eso es una lista de materiales Unicode no una UTF-8. – AnthonyWJones

+0

Gracias, me acabo de dar cuenta de eso. En realidad son 3 bytes, no uno ... Edité la pregunta para decirlo. –

Respuesta

48

con Ruby 1.9.2 se puede utilizar el modo de r:bom|utf-8

text_without_bom = nil #define the variable outside the block to keep the data 
File.open('file.txt', "r:bom|utf-8"){|file| 
    text_without_bom = file.read 
} 

o

text_without_bom = File.read('file.txt', encoding: 'bom|utf-8') 

o

text_without_bom = File.read('file.txt', mode: 'r:bom|utf-8') 

No importa, si la lista de materiales está disponible en el archivo o no.


También puede utilizar la opción de codificación con otros comandos:

text_without_bom = File.readlines(@filename, "r:utf-8") 

(Se obtiene una matriz con todas las líneas).

O con CSV:

require 'csv' 
CSV.open(@filename, 'r:bom|utf-8'){|csv| 
    csv.each{ |row| p row } 
} 
+0

¿Hay alguna manera de hacer esto con archivos CSV utilizando la biblioteca CSV incorporada en ruby? He intentado pasar ': encoding =>" r: bom | utf-8 "' al foreach de CSV, pero todavía lee la lista de materiales como si fuera parte de la primera columna del encabezado. – Aaron

+2

Creo que es posible. Con 'CVS.read (filename,: encoding => 'utf-8')' puede establecer la codificación con CSV (¿o es 'CSV.load'?). Creo que esto también es posible con bom-logic: ': encoding => 'bom | utf-8')'. No puedo probarlo yo mismo, lo siento. – knut

+0

Lo siguiente funcionó para mí: 'file = File.open (@filename, 'r: bom | utf-8')' 'csv = CSV.new (archivo, faster_csv_options)' 'csv.each do | fila | ' ' ... ' ' file.close' – Aaron

10

No omitiría ciegamente los primeros tres bytes; ¿Qué ocurre si el productor detiene y vuelve a agregar la lista de materiales? Lo que debe hacer es examinar los primeros bytes, y si son 0xEF 0xBB 0xBF, ignórelos. Esa es la forma que toma el carácter BOM (U + FEFF) en UTF-8; Prefiero lidiar con esto antes de tratar de decodificar la transmisión porque el manejo de la BOM es tan inconsistente de un idioma/herramienta/estructura a la siguiente.

De hecho, así es como se supone que para hacer frente a una lista de materiales. Si un archivo se ha servido como UTF-16, debe examinar los primeros dos bytes antes de comenzar la decodificación para saber si leerlo como big-endian o little-endian. Por supuesto, la BOM UTF-8 no tiene nada que ver con el orden de bytes, solo está ahí para hacerle saber que la codificación es UTF-8, en caso de que no lo supiera.

0

no me gustaría "confianza" algún archivo a codificar como UTF-8 cuando está presente una lista de materiales de 0xEF 0xBB 0xBF, es posible que no vaya. Por lo general, al detectar la BOM UTF-8, debería ser un archivo codificado en UTF-8, por supuesto. Pero, si, por ejemplo, alguien acaba de agregar la BOM UTF-8 a un archivo ISO, no codificaría ese archivo tan mal si hay bytes en él que están por encima de 0x0F. Puede confiar en el archivo si solo tiene bytes de hasta 0x0F, porque en este caso es un archivo ASCII compatible con UTF-8 y al mismo tiempo es un archivo UTF-8 válido.

Si no hay solo bytes < = 0x0F dentro del archivo (después de la BOM), para asegurarse de que está correctamente codificado en UTF-8, deberá verificar las secuencias válidas e, incluso cuando todas las secuencias sean válidas, también verifique si cada punto de código de una secuencia utiliza la secuencia más corta posible y también verifique si no hay un punto de código que coincida con un sustituto alto o bajo. También verifique si el máximo de bytes de una secuencia no es mayor que 4 y el punto de código más alto es 0x10FFFF. El punto de código más alto también limita los bits de la carga de inicio del inicio de sesión para que no sean superiores a 0x4 y la carga útil del primer byte no sea superior a 0xF. Si todas las comprobaciones mencionadas pasan con éxito, su BOM UTF-8 dice la verdad.

Cuestiones relacionadas