2012-03-21 44 views
7

我的Rails 3.2.2/1.9.3的Ruby應用程序獲取搜索請求,如:確定字符編碼的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-equiv =「content-type」content =「text/html; charset = UTF-8」'

不確定是否有另一種方法告訴客戶端哪些編碼使用?

+0

如果在'app/models/product.rb'的頂部寫'#coding:UTF-8'會怎麼樣?我認爲它應該解決這個錯誤。你會滿意這個解決方案嗎? – ck3g 2012-03-21 06:50:11

+0

@ ck3g,不,這不是關於文件編碼。 – fl00r 2012-03-21 08:11:37

+0

您將不得不使用某種字典來確定正確的編碼,因爲相同的字節0xE7可能(而且確實是)除Latin1以外的其他編碼中的有效字符。 – 2012-03-21 08:15:54

回答

5

字符ç在URL中編碼爲%E7。這是ISO-8859-1如何編碼ç。 ISO-8859-1字符集表示具有單個字節的字符。表示ç的字節可以用十六進制表示爲E7。

在Unicode中,ç的代碼點爲U + 00E7。與代碼點(E7)與其編碼(十六進制中的E7)相同的ISO-8859-1不同,Unicode具有多種編碼方案,如UTF-8,UTF-16和UTF-32。 UTF-8將U + 00E7(ç)編碼爲兩個字節 - C3 A7。

查看here用於編碼ç的其他方式。

至於爲什麼ISO-8859-1中的U + 00E7和E7都使用「E7」,Unicode中的前256個編碼點與ISO-8859-1相同。

如果這個URL是UTF-8,ç會被編碼爲%C3%A7。我對RFC2616的(非常有限的)瞭解是URL的默認編碼是(當前)ISO-8859-1。因此,這很可能是ISO-8859-1編碼的URL。這意味着,最好的辦法可能是檢查的編碼是有效的,如果不是,假設它是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

它似乎是一個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和編碼字符列表實現自己的方法?

+0

你指的是哪些問題? http://ideone.com/hWnj6 – 2012-03-21 11:53:32

+0

@MladenJablanović如果字符串是UTF-8,你應該不需要force_encode latin1然後編碼爲UTF-8嗎?由於%E7是兩個字符集中的一個小C字符,並且有cedilla? 進一步閱讀表明,%C3%A7可能是UTF-8下該字符的正確編碼,而不是%E7。 – dkam 2012-03-21 12:18:05

+0

@MladenJablanović – 2012-03-21 12:33:10