Como evitar tropeçar na lista de materiais UTF-8 ao ler arquivos

Estou consumindo um feed de dados que recentemente adicionou um header Unicode BOM (U + FEFF), e minha tarefa rake agora está confusa com isso.

Eu posso pular os primeiros 3 bytes com file.gets[3..-1] mas existe uma maneira mais elegante de ler arquivos em Ruby que podem lidar com isso corretamente, se uma BOM está presente ou não?

Com ruby ​​1.9.2 você pode usar o 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 } 

ou

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

ou

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

Não importa, se a lista de materiais estiver disponível no arquivo ou não.


Você também pode usar a opção de codificação com outros comandos:

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

(Você recebe um array com todas as linhas).

Ou com o CSV:

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

Eu não ignoraria cegamente os primeiros três bytes; E se o produtor parar de adicionar a lista de materiais novamente? O que você deve fazer é examinar os primeiros bytes, e se eles estiverem 0xEF 0xBB 0xBF, ignore-os. Essa é a forma que o caractere de BOM (U + FEFF) recebe em UTF-8; Eu prefiro lidar com isso antes de tentar decodificar o stream porque o manuseio de BOM é tão inconsistente de um idioma / ferramenta / framework para o próximo.

Na verdade, é assim que você deve lidar com uma lista de materiais. Se um arquivo tiver sido servido como UTF-16, você terá que examinar os dois primeiros bytes antes de começar a decodificação, para saber se deve lê-lo como big-endian ou little-endian. Obviamente, a lista de materiais UTF-8 não tem nada a ver com a ordem de bytes. Ela está lá apenas para informar que a codificação é UTF-8, caso você ainda não saiba disso.

Eu não “confiaria” em algum arquivo para ser codificado como UTF-8 quando um BOM de 0xEF 0xBB 0xBF estiver presente, você poderá falhar. Geralmente, ao detectar a BOM UTF-8, ela deve ser um arquivo codificado em UTF-8, é claro. Mas, se por exemplo alguém acabou de adicionar a BOM UTF-8 a um arquivo ISO, você não conseguirá codificar esse arquivo tão ruim se houver bytes nele acima de 0x0F. Você pode confiar no arquivo se tiver apenas bytes até 0x0F dentro, porque neste caso é um arquivo ASCII compatível com UTF-8 e ao mesmo tempo é um arquivo UTF-8 válido.

Se não houver apenas bytes <= 0x0F dentro do arquivo (após o BOM), para ter certeza de que ele está corretamente codificado em UTF-8 você terá que verificar sequências válidas e - mesmo quando todas as sequências forem válidas - verificar também se cada codepoint de uma seqüência usa a seqüência mais curta possível e verifica também se não há um codepoint que corresponda a um substituto alto ou baixo. Verifique também se o máximo de bytes de uma sequência não é maior que 4 e o maior ponto de código é 0x10FFFF. O ponto de código mais alto limita também os bits de carga útil do início do processo a não serem superiores a 0x4 e a carga útil do primeiro byte seguinte não superior a 0xF. Se todas as verificações mencionadas passarem com sucesso, sua lista de materiais UTF-8 diz a verdade.