SmarterCSV и проблемы с кодировкой файлов в Ruby

Я работаю с файлом, который, кажется, имеет кодировку UTF-16LE. Если я бегу

File.read(file, :encoding => 'utf-16le')

первая строка файла:

"<U+FEFF>=\"25/09/2013\"\t18:39:17\t=\"Unknown\"\t=\"+15168608203\"\t\"Message.\"\r\n

Если я читаю файл, используя что-то вроде

csv_text = File.read(file, :encoding => 'utf-16le')

Я получаю сообщение об ошибке

ASCII incompatible encoding needs binmode (ArgumentError)

Если я переключу кодировку в приведенном выше

csv_text = File.read(file, :encoding => 'utf-8')

Я делаю это к SmarterCSV часть кода, но появляется сообщение об ошибке

`=~': invalid byte sequence in UTF-8 (ArgumentError)

Полный код ниже. Если я запускаю это в консоли Rails, он работает просто отлично, но если я запускаю его, используя ruby test.rb, это дает мне первую ошибку:

require 'smarter_csv'
headers = ["date_of_message", "timestamp_of_message", "sender", "phone_number", "message"]
path = '/path/'
Dir.glob("#{path}*.CSV").each do |file|
  csv_text = File.read(file, :encoding => 'utf-16le')
  File.open('/tmp/tmp_file', 'w') { |tmp_file| tmp_file.write(csv_text) }
  puts 'made it here'
  SmarterCSV.process('/tmp/tmp_file', {
    :col_sep => "\t",
    :force_simple_split => true,
    :headers_in_file => false,
    :user_provided_headers => headers
   }).each do |row|
    converted_row = {}
    converted_row[:date_of_message] = row[:date_of_message][2..-2].to_date
    converted_row[:timestamp] = row[:timestamp]
    converted_row[:sender] = row[:sender][2..-2]
    converted_row[:phone_number] = row[:phone_number][2..-2]
    converted_row[:message] = row[:message][1..-2]
    converted_row[:room] = file.gsub(path, '')
  end
end

Обновление - 13.05.15

В конечном итоге я решил закодировать строку файла как UTF-8, а не углубляться в код SmarterCSV. Первая проблема в коде SmarterCSV состоит в том, что он не позволяет пользователю указывать двоичный режим при чтении в файле, но после настройки источника для обработки этого возникает множество других проблем, связанных с кодированием, многие из которых связаны с к обработке различных параметров в файлах, которые не были в кодировке UTF-8. Возможно, это был простой выход, но моя проблема была решена с помощью кодирования всего в UTF-8 до подачи его в SmarterCSV.

2 ответа

Решение

Добавьте binmode к File.read вызов.

File.read(file, :encoding => 'utf-16le', mode: "rb")

Режим двоичного файла "b" Подавляет преобразование EOL <-> CRLF в Windows. И устанавливает внешнее кодирование в ASCII-8BIT, если явно не указано.

ссылка: http://ruby-doc.org/core-2.0.0/IO.html

Теперь передайте правильную кодировку в SmarterCSV

SmarterCSV.process('/tmp/tmp_file', {
:file_encoding => "utf-16le", ...

Обновить

Было установлено, что smartercsv не поддерживает бинарный режим. После того, как ОП попытался изменить код безуспешно, было решено, что простым решением было преобразовать входные данные в UTF-8 который smartercsv поддерживает.

К сожалению, вы используете стиль хранения "плоский файл", и кодирование символов будет проблемой с обеих сторон (чтение или запись).

Я бы предложил использовать что-то вроде str = str.force_encoding("UTF-8") и посмотрим, сможете ли вы заставить это работать.

Другие вопросы по тегам