首页 文章

确定Ruby 1.9.3中的字符编码

提问于
浏览
7

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*')

处理这个问题的正确方法是什么?

Edit 服务器正在向客户端正确发送"Content-Type: text/html; charset=utf-8"标头 . 该页面还包含相应的元标记:'meta http-equiv= 2595953 content= 2595954 '

不确定是否有另一种方法告诉客户端使用哪种编码?

2 回答

  • 0

    字符ç在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 .

    有关编码ç的其他方法,请参见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"
    
  • 5

    它似乎是一个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和编码字符列表实现自己的方法?

相关问题