open-uri, возвращающий ASCII-8BIT со страницы, закодированной в iso-8859 - PullRequest
6 голосов
/ 19 апреля 2011

Я использую open-uri для чтения веб-страницы, которая утверждает, что она закодирована в iso-8859-1. Когда я читаю содержимое страницы, open-uri возвращает строку, закодированную в ASCII-8BIT.

open("http://www.nigella.com/recipes/view/DEVILS-FOOD-CAKE-5310") {|f| p f.content_type, f.charset, f.read.encoding }
 => ["text/html", "iso-8859-1", #<Encoding:ASCII-8BIT>] 

Я предполагаю, что это потому, что веб-страница имеет байт (или символ) \ x92, который не является допустимым символом ISO-8859. http://en.wikipedia.org/wiki/ISO/IEC_8859-1.

Мне нужно хранить веб-страницы как файлы в кодировке utf-8. Любые идеи о том, как бороться с веб-страницей, где кодировка неверна. Я мог бы поймать исключение и попытаться угадать правильную кодировку, но это кажется громоздким и подверженным ошибкам.

1 Ответ

7 голосов
/ 23 июня 2011
  • ASCII-8BIT is an alias for BINARY
  • open-uri делает забавную вещь: если файл меньше 10 КБ (или что-то в этом роде), он возвращает String, а если он больше, то возвращает StringIO. Это может сбивать с толку, если вы пытаетесь решить проблемы с кодировкой.

Если файлы не очень большие, я бы рекомендовал вручную загружать их в строки:

require 'uri'
require 'net/http'
require 'net/https'

uri = URI.parse url_to_file

http = Net::HTTP.new(uri.host, uri.port)
if uri.scheme == 'https'
  http.use_ssl = true
  # possibly useful if you see ssl errors
  # http.verify_mode = ::OpenSSL::SSL::VERIFY_NONE
end
body = http.start { |session| session.get uri.request_uri }.body

Тогда вы можете использовать https://rubygems.org/gems/ensure-encoding самоцвет

require 'ensure/encoding'
utf8_body = body.ensure_encoding('UTF-8', :external_encoding => :sniff, :invalid_characters => :transcode)

Я был очень доволен ensure-encoding ... мы используем его в производстве на http://data.brighterplanet.com

Обратите внимание, что вы также можете сказать :invalid_characters => :ignore вместо :transcode.

Также, если вы знаете кодировку, вы можете передать :external_encoding => 'ISO-8859-1' вместо :sniff

...