2012-03-21 8 views
7

Mis Rails 3.2.2/1.9.3 de Ruby aplicación obtiene solicitudes de búsqueda, tales como:Determinar la codificación de caracteres en Ruby 1.9.3

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

Rubí/Carriles toma esta consulta y la decodifica - pero asume que es UTF 8. En algún momento me sale un:

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

Creo que es hacer algo como esto:

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 

Cuál es la forma correcta de hacer frente a esto? Me gustaría transcodificarlo a la codificación correcta, pero ¿cómo determino la codificación actual? Lo que estoy haciendo actualmente, se acaba asumiendo que es LATIN1:

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

o hacer algo que encontré en un blog en alguna parte:

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

¿Cuál es la manera correcta de hacer frente a esto?

Editar El servidor está enviando correctamente "Content-Type: text html /; charset = UTF-8" de cabecera para el cliente. La página también contiene la metaetiqueta adecuada: 'meta http-equiv = "tipo de contenido" content = "text/html; charset = UTF-8"'

No estoy seguro si hay otro método para decirle al cliente qué codificaciones ¿usar?

+0

¿Qué pasaría si escribes '#coording: UTF-8' en la parte superior de' app/models/product.rb'. Creo que debería resolver ese error. ¿Estará satisfecho con esta solución? – ck3g

+0

@ ck3g, no, no se trata de la codificación de archivos aquí. – fl00r

+0

Debería utilizar algún tipo de diccionario para determinar la codificación correcta, ya que el mismo byte '0xE7' podría ser (y de hecho es) un carácter válido en codificaciones distintas de Latin1. –

Respuesta

5

El carácter ç está codificado en la URL como% E7. Así es como codifica ISO-8859-1 ç. El juego de caracteres ISO-8859-1 representa un personaje con un solo byte. El byte que representa ç puede expresarse en hexadecimal como E7.

En Unicode, ç tiene un punto de código de U + 00E7. A diferencia de ISO-8859-1, en el que el punto de código (E7) es el mismo que su codificación (E7 en hexadecimal), Unicode tiene múltiples esquemas de codificación como UTF-8, UTF-16 y UTF-32. UTF-8 codifica U + 00E7 (ç) como dos bytes - C3 A7.

Vea here para conocer otras formas de codificar ç.

En cuanto a por qué U + 00E7 y E7 en ISO-8859-1 usan "E7", los primeros 256 puntos de código en Unicode se hicieron idénticos a ISO-8859-1.

Si esta URL fuera UTF-8, se codificará como% C3% A7. Mi comprensión (muy limitada) de RFC2616 es que la codificación predeterminada para una URL es (actualmente) ISO-8859-1. Por lo tanto, esto es más probable URL codificada ISO-8859-1.Lo que significa, el mejor enfoque es, probablemente, para comprobar que la codificación es válida y si no, asuma que se ISO-8859-1 y transcodificar a UTF-8:

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

Aquí es el proceso en el IRB (más una escapando al final por diversión)

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

Parece que es una cadena codificada en url. Como referencia aquí es una lista de caracteres codificados: http://www.degraeve.com/reference/urlencoding.php

Desafortunadamente la biblioteca CGI tiene problemas con UTF-8, y si los métodos unescape funciona bien con algunos personajes como el espacio, que no funciona bien con los demás.

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 

¿Tal vez puede implementar su propio método usando gsub y la lista de caracteres codificados?

+0

¿A qué problemas se refiere? http://ideone.com/hWnj6 –

+0

@ MladenJablanović si la cadena es UTF-8, no debería necesitar forzar el código para latin1 y luego codificar para UTF-8, ¿verdad? ¿Como% E7 es una C pequeña con cedilla en ambos conjuntos de caracteres? La lectura adicional sugeriría que% C3% A7 puede ser la codificación correcta para este carácter en UTF-8, en lugar de% E7. – dkam

+0

@Mladen Jablanović –

Cuestiones relacionadas