Come evitare di inciampare su BOM UTF-8 durante la lettura dei file

Sto consumando un feed di dati che ha recentemente aggiunto un’intestazione BOM Unicode (U + FEFF), e la mia attività di rake è ora incasinata da esso.

Posso saltare i primi 3 byte con file.gets[3..-1] ma c’è un modo più elegante di leggere i file in Ruby che possono gestirli correttamente, se una distinta base è presente o no?

Con Ruby 1.9.2 puoi usare la modalità 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') 

Non importa, se la distinta base è disponibile nel file o no.


Puoi anche usare l’opzione di codifica con altri comandi:

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

(Ottieni un array con tutte le linee).

Oppure con CSV:

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

Non salterò ciecamente i primi tre byte; cosa succede se il produttore interrompe l’ aggiunta della BOM? Quello che dovresti fare è esaminare i primi pochi byte, e se sono 0xEF 0xBB 0xBF, ignorali. Questa è la forma in cui il carattere BOM (U + FEFF) assume UTF-8; Preferisco occuparmene prima di tentare di decodificare lo stream perché la gestione delle distinte base è così incoerente da una lingua / strumento / framework a quella successiva.

In effetti, è così che dovresti trattare con una BOM. Se un file è stato pubblicato come UTF-16, devi esaminare i primi due byte prima di iniziare la decodifica in modo da sapere se leggerlo come big-endian o little-endian. Ovviamente, il BOM UTF-8 non ha nulla a che fare con l’ordine dei byte, è solo lì per farti sapere che la codifica è UTF-8, nel caso in cui non lo sapessi già.

Non mi “fidavo” del file da codificare come UTF-8 quando è presente una distinta di 0xEF 0xBB 0xBF, potresti fallire. Di solito, quando si rileva il BOM UTF-8, dovrebbe essere un file con codifica UTF-8, ovviamente. Ma, se per esempio qualcuno ha appena aggiunto il BOM UTF-8 a un file ISO, non riuscirai a codificare tale file così male se ci sono dei byte al di sopra di 0x0F. Puoi fidarti del file se hai solo byte fino a 0x0F all’interno, perché in questo caso è un file ASCII compatibile con UTF-8 e allo stesso tempo è un file UTF-8 valido.

Se non ci sono solo byte <= 0x0F all'interno del file (dopo la distinta componenti), per essere certi che sia codificato in UTF-8, è necessario verificare le sequenze valide e, anche quando tutte le sequenze sono valide, controllare anche se ciascuna il punto di codice da una sequenza utilizza la sequenza più breve possibile e controlla anche se non c'è alcun punto di codice che corrisponda a un surrogato alto o basso. Controlla anche se il numero massimo di byte di una sequenza non è superiore a 4 e il codice più alto è 0x10FFFF. Il più alto punto di codice limita anche i bit del payload del startbyte non superiore a 0x4 e il carico utile del primo byte successivo non superiore a 0xF. Se tutti i controlli citati vengono trasmessi correttamente, il BOM UTF-8 indica la verità.