Ruby 2.0.0 String#Match ArgumentError:неверная последовательность байтов в UTF-8
-
21-12-2019 - |
Вопрос
Я вижу это часто и не нашел изящного решения.Если пользовательский ввод содержит недопустимые последовательности байтов, мне нужно, чтобы он не вызывал исключения.Например:
# @raw_response comes from user and contains invalid UTF-8
# for example: @raw_response = "\xBF"
regex.match(@raw_response)
ArgumentError: invalid byte sequence in UTF-8
Было задано множество подобных вопросов, и результатом, похоже, является кодирование или принудительное кодирование строки.Однако ни один из них не работает для меня:
regex.match(@raw_response.force_encoding("UTF-8"))
ArgumentError: invalid byte sequence in UTF-8
или
regex.match(@raw_response.encode("UTF-8", :invalid=>:replace, :replace=>"?"))
ArgumentError: invalid byte sequence in UTF-8
Это ошибка Ruby 2.0.0 или я что-то упускаю?
Что странно, так это то, что кодирование выглядит правильно, но совпадение продолжает вызывать исключение:
@raw_response.encode("UTF-8", :invalid=>:replace, :replace=>"?").encoding
=> #<Encoding:UTF-8>
Решение
В Руби 2.0 encode
метод является неактивным при кодировании строки в ее текущую кодировку:
Обратите внимание, что преобразование из кодировки
enc
в ту же кодировкуenc
является недействующей операцией, т.е.получатель возвращается без каких-либо изменений, и никаких исключений не возникает, даже если есть недопустимые байты.
Это изменилось в версии 2.1, в которой также был добавлен scrub
метод как более простой способ сделать это.
Если вы не можете обновиться до версии 2.1, вам придется закодировать другую кодировку и вернуться обратно, чтобы удалить недопустимые байты, например:
if ! s.valid_encoding?
s = s.encode("UTF-16be", :invalid=>:replace, :replace=>"?").encode('UTF-8')
end
Другие советы
С тех пор, как вы используете Rails, а не просто Ruby, вы также можете использовать tidy_bytesЭто работает с Ruby 2.0, а также, вероятно, даст вам разумные данные, а не только для замены символов.