Строка#encode не исправлена ошибка" недопустимая последовательность байтов в UTF-8"
Я знаю, что существует множество подобных вопросов об этой ошибке, и я пробовал многие из них без успеха. Проблема, с которой я сталкиваюсь, включает байт xA1
и бросает
ArgumentError: недопустимая последовательность байтов в UTF-8
Я попробовал следующее, но безуспешно:
"xA1".encode('UTF-8', :undef => :replace, :invalid => :replace,
:replace => "").sub('', '')
"xA1".encode('UTF-8', :undef => :replace, :invalid => :replace,
:replace => "").force_encoding('UTF-8').sub('', '')
"xA1".encode('UTF-8', :undef => :replace, :invalid => :replace,
:replace => "").encode('UTF-8').sub('', '')
Каждая строка выдает ошибку за меня. Что я делаю не так?
Обновление:
Приведенных выше строк не только в СИБ. Однако я изменил свое приложение для кодирования строки файла CVS, использующие тот же метод#encode и аргументы, и я получаю ту же ошибку при чтении строки из файла (Примечание: это работает, если вы выполняете операции над той же строкой без использования IO).
bad_line = "col1tcol2tbadxa1"
bad_line.sub('', '') # does NOT fail
puts bad_line # => col1 col2 bad?
tmp = Tempfile.new 'foo' # write the line to a file to emulate real problem
tmp.puts bad_line
tmp.close
tmp2 = Tempfile.new 'bar'
begin
IO.foreach tmp.path do |line|
line.encode!('UTF-8', :undef => :replace, :invalid => :replace, :replace => "")
line.sub('', '') # fail: invalid byte sequence in UTF-8
tmp2.puts line
end
tmp2.close
# this would fail if the above error didn't halt execution
CSV.foreach(tmp2.path) do |row|
puts row.inspect # fail: invalid byte sequence in UTF-8
end
ensure
tmp.unlink
tmp2.close
tmp2.unlink
end
2 ответа:
Похоже, что ruby думает, что кодировка строки уже utf8, поэтому когда вы делаете
line.encode!('UTF-8', :undef => :replace, :invalid => :replace, :replace => "")
На самом деле он ничего не делает, потому что кодировка назначения совпадает с текущей кодировкой (по крайней мере, это моя интерпретация кода в
Реальный вопрос здесь заключается в том, допустимы ли ваши исходные данные в какой-то кодировке, которая не является utf-8, или это данные, которые должны быть utf-8, но в них есть несколько бородавок, которые вы хотите отбросить.transcode.c
)В в первом случае правильнее всего будет сказать ruby, что это за кодировка. Вы можете сделать это, когда откроете файл
File.open('somefile', 'r:iso-8859-1')
Откроет файл, интерпретируя его содержимое как iso-8859-1
Вы даже можете заставить ruby перекодировать для вас
File.open('somefile', 'r:iso-8859-1:utf-8')
Откроет файл как iso-8859-1, но при чтении данных из него байты будут преобразованы в utf-8 для вас.
Вы также можете вызвать
force_encoding
, чтобы сообщить ruby, что такое кодировка строки (это не изменяет байты вообще, это просто говорит руби, как их интерпретировать).Во втором случае, когда вы просто хотите сбросить все неприятные вещи, попавшие в ваш utf-8, вы не можете просто вызвать
encode!
, потому что это не op. в ruby 2.1 и выше, вы можете использовать String#scrub , в предыдущих версиях вы можете сделать этоline.encode!('UTF-16', :undef => :replace, :invalid => :replace, :replace => "") line.encode!('UTF-8')
Мы сначала преобразуем в utf-16. Поскольку это другая кодировка, ruby фактически заменит наши недопустимые последовательности. Затем мы можем вернуться к utf-8. От этого мы ничего не потеряем. дополнительные данные, потому что utf-8 и utf-16-это просто два разных способа кодирования одного и того же базового набора символов.