Определить кодировку символов в Ruby 1.9.3 - PullRequest
7 голосов
/ 21 марта 2012

My Rails 3.2.2 / Ruby 1.9.3 приложение получает поисковые запросы, такие как:

http://booko.com.au/books/search?q=Fran%E7ois+Vergniolle+de+Chantal

Ruby / Rails принимает этот запрос и декодирует его, но предполагает, что это UTF-8.В какой-то момент я получаю:

invalid byte sequence in UTF-8
app/models/product.rb:694:in `upcase' 

Я думаю, что он делает что-то вроде этого:

q="Fran%E7ois+Vergniolle+de+Chantal"
=> "Fran%E7ois+Vergniolle+de+Chantal"

CGI.unescape( q )
=> "Fran\xE7ois Vergniolle de Chantal"

CGI.unescape( q ).encoding.name
=> "UTF-8"

CGI.unescape( q ).valid_encoding?
=> false

Как правильно с этим справиться?Я хотел бы перекодировать его в правильную кодировку, но как определить текущую кодировку?То, что я сейчас делаю, просто предполагает, что это LATIN1:

q.encode!("ISO-8859-1", "UTF-8", :invalid => :replace, :undef => :replace, :replace => "")

Или делает что-то, что я нашел в блоге где-то:

q = q.unpack('C*').pack('U*')

Какой правильный способ борьбы с этим?

Редактировать Сервер правильно отправляет клиенту заголовок «Content-Type: text / html; charset = utf-8».Страница также содержит соответствующий метатег: 'meta http-equ = "content-type" content = "text / html; charset = UTF-8"'

Не уверен, есть ли другой способ сообщить клиентукакие кодировки использовать?

Ответы [ 2 ]

5 голосов
/ 22 марта 2012

Символ ç закодирован в URL как% E7.Вот как ISO-8859-1 кодирует.Набор символов ISO-8859-1 представляет символ с одним байтом.Байт, который представляет ç, может быть выражен в шестнадцатеричном виде как E7.

В Unicode ç имеет кодовую точку U + 00E7.В отличие от ISO-8859-1, в котором кодовая точка (E7) совпадает с кодировкой (E7 в шестнадцатеричном формате), Unicode имеет несколько схем кодирования, таких как UTF-8, UTF-16 и UTF-32.UTF-8 кодирует U + 00E7 (ç) как два байта - C3 A7.

См. здесь для других способов кодирования ç.

Что касается того, почему U + 00E7 и E7 в ISO-8859-1 оба используют «E7», первые 256 кодовых точек в Unicode были сделаны идентичными ISO-8859-1 .

Если бы этот URL был UTF-8, ç был бы закодирован как% C3% A7.Мое (очень ограниченное) понимание RFC2616 заключается в том, что кодировкой по умолчанию для URL является (в настоящее время) ISO-8859-1.Следовательно, это, скорее всего, URL-код в формате ISO-8859-1.Это означает, что наилучшим подходом, вероятно, является проверка правильности кодировки, а если нет, то предположим, что это ISO-8859-1 и транскодирование в UTF-8:

unless query.valid_encoding?
    query.encode!("UTF-8", "ISO-8859-1", :invalid => :replace, :undef => :replace, :replace => "")
end

Вот процесс в IRB (плюс побег в конце для развлечения)

a = CGI.unescape("%E7")
=> "\xE7"
a.encoding
=> #<Encoding:UTF-8>
a.valid_encoding?
=> false
b = a.encode("UTF-8", "ISO-8859-1")    # From ISO-8859-1 -> UTF-8
=> "ç"
b.encoding
=> #<Encoding:UTF-8>
CGI.escape(b)
=> "%C3%A7"
0 голосов
/ 21 марта 2012

Кажется, что это строка в кодировке URL.Для справки вот список закодированных символов: http://www.degraeve.com/reference/urlencoding.php

К сожалению, в библиотеке CGI есть проблемы с utf-8, и если методы unescape хорошо работают с одними символами, такими как пробел, они не работают хорошо с другими.

require'cgi'
a = "Fran%E7ois+Vergniolle+de+Chantal"
a= a.gsub('+', ' ').gsub('%E7','ç')
puts a
=> François Vergniolle de Chantal

a = "Fran%E7ois+Vergniolle+de+Chantal"
a = CGI::unescape(a) 
puts a
=> Franis Vergniolle de Chantal

Может быть, вы можете реализовать свой собственный метод, используя gsub и список закодированных символов?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...