Как избежать отключения по спецификации UTF-8 при чтении файлов - PullRequest
38 голосов
/ 12 февраля 2009

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

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

Ответы [ 3 ]

60 голосов
/ 16 октября 2011

С 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 }
}
10 голосов
/ 13 февраля 2009

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

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

0 голосов
/ 03 июня 2013

Я бы не "доверял" какому-либо файлу, который будет закодирован как 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 говорит правду. </p>

...