Подтвердить что ты не робот

Как избежать опрокидывания спецификации UTF-8 при чтении файлов

Я использую фид данных, который недавно добавил заголовок спецификации Юникода (U + FEFF), и моя задача рейка теперь перепутана.

Я могу пропустить первые 3 байта с помощью file.gets[3..-1], но есть ли более элегантный способ чтения файлов в Ruby, который может справиться с этим правильно, независимо от того, присутствует ли спецификация?

4b9b3361

Ответ 1

С ruby ​​1.9.2 вы можете использовать режим 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
}

или

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

или

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

Это не имеет значения, если спецификация доступна в файле или нет.


Вы также можете использовать опцию кодирования с другими командами:

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

(Вы получаете массив со всеми строками).

Или с CSV:

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

Ответ 2

Я бы не слепо пропустил первые три байта; что, если производитель перестанет добавлять спецификацию снова? Вам следует изучить первые несколько байтов, и если они равны 0xEF 0xBB 0xBF, игнорируйте их. То, что форма BOM-символа (U + FEFF) принимает в UTF-8; Я предпочитаю иметь дело с ним, прежде чем пытаться декодировать поток, потому что обработка спецификации настолько несовместима с одним языком/инструментом/структурой до следующего.

Фактически, это то, как вы должны иметь дело с спецификацией. Если файл был подан как UTF-16, перед началом декодирования вам нужно проверить первые два байта, чтобы вы знали, следует ли считать его как big-endian или little-endian. Разумеется, спецификация UTF-8 не имеет ничего общего с порядком байтов, она просто там, чтобы вы знали, что кодировка UTF-8, если вы этого еще не знали.

Ответ 3

Я не буду "доверять" некоторому файлу, который будет закодирован как UTF-8, когда присутствует спецификация 0xEF 0xBB 0xBF, вы можете выйти из строя. Обычно при обнаружении спецификации UTF-8, это действительно должен быть файл с кодировкой UTF-8, конечно. Но, если, например, кто-то только что добавил спецификацию UTF-8 в файл ISO, вы не смогли бы так плохо кодировать такой файл, если в нем есть байты, которые превышают 0x0F. Вы можете доверять файлу, если у вас есть только байты до 0x0F внутри, потому что в этом случае это ASCII файл, совместимый с UTF-8, и в то же время он является допустимым файлом UTF-8.

Если в файле есть не только байты <= 0x0F (после спецификации), чтобы убедиться, что он правильно закодирован в кодировке UTF-8, вам нужно будет проверить допустимые последовательности и - даже если все последовательности действительны - проверьте также, если каждый код из последовательности использует кратчайшую возможную последовательность и также проверяет, нет ли кодового пункта, который соответствует высокому или низкому суррогату. Также проверьте, не превышает ли максимальные байты последовательности не более 4, а самый высокий код - 0x10FFFF. Наивысший уровень кодирования ограничивает также биты полезной нагрузки старшего байт не выше 0x4 и первую полезную нагрузку байта не выше 0xF. Если все упомянутые проверки успешно пройдены, ваша спецификация UTF-8 говорит правду.