Cómo evitar tropezar con la BOM UTF-8 al leer archivos

Estoy consumiendo un feed de datos que recientemente agregó un encabezado de lista de materiales Unicode (U + FEFF), y mi tarea de rake ahora está arruinada.

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

Con ruby ​​1.9.2 puedes usar el modo 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 usar la opción de encoding con otros comandos:

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

(Obtienes 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 } } 

No omitiría ciegamente los primeros tres bytes; ¿Qué pasa si el productor deja de agregar la lista de materiales de nuevo? 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 debes lidiar con una lista de materiales. Si un archivo se ha servido como UTF-16, debe examinar los primeros dos bytes antes de comenzar la deencoding 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 encoding es UTF-8, en caso de que no lo supiera.

No confío en que algún archivo se codifique como UTF-8 cuando hay una lista de materiales de 0xEF 0xBB 0xBF, puede fallar. 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á codificado en UTF-8 correctamente, tendrá que verificar las secuencias válidas e, incluso cuando todas las secuencias sean válidas, también verifique si cada una El punto de código de una secuencia utiliza la secuencia más corta posible y también verifica 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.