Ruby on Rails: Net::HTTP, ASCII-8BIT и UTF-8 — приключения кириллицы

Вот уже пару месяцев я работаю над своим дипломным проектом. В чем там суть пока раскрывать не буду, но проект на Ruby on Rails – давно уже хотелось посмотреть, что это и с чем его едят. Впечатления сплошь положительные, и лишь один момент с кодировками заставил меня поматериться – об этом и пойдет речь.

Суть проблемы

Я получаю данные с разных сайтов через

1
response = Net::HTTP.get_response(URI.parse(URI.encode(url)))
response = Net::HTTP.get_response(URI.parse(URI.encode(url)))

Дальше обрабатываю response.body, и все в теории красиво. Но при наличии среди полученных данных кириллицы я в базе получала совсем не то, что хотелось, а что-то типа «\xCB» вместо кириллического символа. На базу грешить не приходится, при сохранении кириллицы обычным post’ом проблем нет. Значит дело в самих данных.

Попытки решения

response.body имеет кодировку ASCII-8BIT. Дефолтная кодировка проекта UTF-8.

1
response.body.encode!
response.body.encode!

ничего не изменил

1
2
response.body.encode('utf-8', 'binary', :invalid => :replace,
:undef => :replace, :replace => '')
response.body.encode('utf-8', 'binary', :invalid => :replace,
:undef => :replace, :replace => '')

– просто выпиливает кириллицу

1
response.body.force_encoding("UTF-8)
response.body.force_encoding("UTF-8)

– возвращает ерунуду со знаками вопроса вместо кириллицы

Поочередное преобразование

1
2
response.body.force_encoding("windows-1251)
response.body.encode!
response.body.force_encoding("windows-1251)
response.body.encode!

для некоторых сайтов сработало, но все же часто возвращало ������. Как так? Везде charset=UTF-8. Но раз преобразование к windows-1251 помогло, надо танцевать отсюда.

И вот оно, чудо!

Окончательным решением вопроса стала вот такая обработка:

1
2
3
4
5
6
7
8
9
begin
cleaned = response.body.dup.force_encoding('UTF-8')
unless cleaned.valid_encoding?
cleaned = response.body.encode( 'UTF-8', 'Windows-1251' )
end
content = cleaned
rescue EncodingError
content.encode!( 'UTF-8', invalid: :replace, undef: :replace )
end
begin
cleaned = response.body.dup.force_encoding('UTF-8')
unless cleaned.valid_encoding?
cleaned = response.body.encode( 'UTF-8', 'Windows-1251' )
end
content = cleaned
rescue EncodingError
content.encode!( 'UTF-8', invalid: :replace, undef: :replace )
end

Спасибо гуглу)

Понравился пост? Подпишитесь на обновления блога!
Или читайте в Twitter!

Comments are closed.