CSV BOM Ruby | Кодировка UTF-8 для StringIO
Рубин 2.6.3.
Я пытался разобрать StringIO
объект в CSV
экземпляр с bom|utf-8
кодирование, так что символ спецификации (нежелательный) удаляется, а содержимое кодируется в UTF-8:
require 'csv'
CSV_READ_OPTIONS = { headers: true, encoding: 'bom|utf-8' }.freeze
content = StringIO.new("\xEF\xBB\xBFid\n123")
first_row = CSV.parse(content, CSV_READ_OPTIONS).first
first_row.headers.first.include?("\xEF\xBB\xBF") # This returns true
Видимо bom|utf-8
кодировка не работает для StringIO
объекты, но я обнаружил, что это работает для файлов, например:
require 'csv'
CSV_READ_OPTIONS = { headers: true, encoding: 'bom|utf-8' }.freeze
# File content is: "\xEF\xBB\xBFid\n12"
first_row = CSV.read('bom_content.csv', CSV_READ_OPTIONS).first
first_row.headers.first.include?("\xEF\xBB\xBF") # This returns false
Учитывая, что мне нужно работать с StringIO
прямо, почему CSV
игнорирует bom|utf-8
кодировка? Есть ли способ удалить символ спецификации изStringIO
пример?
Спасибо!
3 ответа
Ruby 2.7 добавил set_encoding_by_bom
способ IO
. Этот метод использует метку порядка байтов и устанавливает кодировку.
require 'csv'
require 'stringio'
CSV_READ_OPTIONS = { headers: true }.freeze
content = StringIO.new("\xEF\xBB\xBFid\n123")
content.set_encoding_by_bom
first_row = CSV.parse(content, **CSV_READ_OPTIONS).first
first_row.headers.first.include?("\xEF\xBB\xBF")
#=> false
Я обнаружил, что принудительное кодирование в utf8 на StringIO string
и удаление спецификации для создания нового StringIO сработало:
require 'csv'
CSV_READ_OPTIONS = { headers: true}.freeze
content = StringIO.new("\xEF\xBB\xBFid\n123")
csv_file = StringIO.new(content.string.force_encoding('utf-8').sub("\xEF\xBB\xBF", ''))
first_row = CSV.parse(csv_file, CSV_READ_OPTIONS).first
first_row.headers.first.include?("\xEF\xBB\xBF") # => false
В encoding
вариант больше не нужен. Возможно, это не лучший вариант с точки зрения памяти, но он работает.
Руби не любит спецификации. Он обрабатывает их только при чтении файла, больше нигде, и даже тогда он только читает их, чтобы от них можно было избавиться. Если вам нужна спецификация для вашей строки или спецификация при записи файла, вы должны обработать ее вручную.
Для этого, вероятно, есть драгоценные камни, хотя это легко сделать самому
if string[0...3] == "\xef\xbb\xbf"
string = string[3..-1].force_encoding('UTF-8')
elsif string[0...2] == "\xff\xfe"
string = string[2..-1].force_encoding('UTF-16LE')
# etc