Acabo de actualizar de ruby 1.9.2 a ruby 1.9.3p0 (revisión 2011-10-30 33570). La aplicación My rails usa postgresql como base de datos. La configuración regional del sistema es UTF8, al igual que la codificación de la base de datos. La codificación predeterminada de la aplicación de rieles también es UTF8. Tengo usuarios chinos que ingresan caracteres chinos, así como caracteres en inglés. Las cadenas se almacenan como cadenas codificadas en UTF8. VersiónRieles: problemas de codificación con valores hash serializados a pesar de UTF8
Rieles: 3.0.9
Desde la actualización de algunas de las cadenas chinas existentes en la base de datos ya no se muestran correctamente. Esto no afecta a todas las cadenas, sino solo a aquellas que forman parte de un hash serializado. Todas las otras cadenas que se almacenan como cadenas simples todavía parecen ser correctas.
Ejemplo:
Este es un hash serializado que se almacena como una cadena UTF8 en la base de datos:
broken = "--- !map:ActiveSupport::HashWithIndifferentAccess \ncheckbox: \"1\"\nchoice: \"Round Paper Clips \\xEF\\xBC\\x88\\xE5\\x9B\\x9E\\xE5\\xBD\\xA2\\xE9\\x92\\x88\\xEF\\xBC\\x89\\r\\n\"\ninfo: \"10\\xE7\\x9B\\x92\"\n"
el fin de convertir esta cadena para un hash rubí, I deserializarlo con YAML.load
:
broken_hash = YAML.load(broken)
Esto devuelve un hash con contenidos confusos:
{"checkbox"=>"1", "choice"=>"Round Paper Clips ï¼\u0088å\u009B\u009Eå½¢é\u0092\u0088ï¼\u0089\r\n", "info"=>"10ç\u009B\u0092"}
El material ilegible se supone que es UTF-8 codificados chino. broken_hash['info'].encoding
me dice que ruby piensa que esto es #<Encoding:UTF-8>
. Estoy en desacuerdo.
Curiosamente, todas las demás cadenas que no se serializaron antes se ven bien, sin embargo. En el mismo registro, un campo diferente contiene caracteres chinos que se ven exactamente en la consola de rieles, la consola psql y el navegador. Cada cadena --- no importa si es un hash serializado o cadena simple --- guardada en la base de datos ya que la actualización también se ve bien.
Me trataron de convertir el texto ilegible de una posible codificación equivocada (como GB2312 o ANSI) a UTF-8 a pesar de la afirmación de rubí que esto ya era UTF-8 y por supuesto que no. Este es el código que utilicé:
require 'iconv'
Iconv.conv('UTF-8', 'GB2312', broken_hash['info'])
Esta falla porque rubí no sabe qué hacer con secuencias de ilegales en la cadena.
Realmente solo quiero ejecutar un script para arreglar todas las antiguas cadenas de hash serializadas presumiblemente rotas y terminarlo. ¿Hay alguna manera de convertir estas cuerdas rotas a algo parecido al chino otra vez?
Soy el mejor jugador con el codificada UTF-8 cadena en la cadena de texto (llamados "roto" en el ejemplo anterior). Esta es la cadena china que está codificado en la cadena serializada:
chinese = "\\xEF\\xBC\\x88\\xE5\\x9B\\x9E\\xE5\\xBD\\xA2\\xE9\\x92\\x88\\xEF\\xBC\\x89\\r\\n\"
me di cuenta de que es fácil de convertir esto en una verdadera cadena codificada UTF-8 por la representación no literal que (la eliminación de las barras invertidas de escape).
chinese_ok = "\xEF\xBC\x88\xE5\x9B\x9E\xE5\xBD\xA2\xE9\x92\x88\xEF\xBC\x89\r\n"
Esto devuelve una adecuada cadena china de codificación UTF-8: "(回形针)\r\n"
se desmorona cuando utilizo YAML.load(...)
para convertir la cadena en un hash rubí. Tal vez debería procesar la cadena sin procesar antes de alimentarlo al YAML.load
. Simplemente me pregunto por qué esto es tan ...
¡Interesante! Esto probablemente se deba al motor "psych" de YAML que se usa por defecto ahora en 1.9.3. Cambié al motor "syck" con YAML::ENGINE.yamler = 'syck'
y las cadenas rotas se analizaron correctamente.
¿Cuál es el tipo de columna para los hash serializados? –
@muistooshort: el tipo de columna es 'text'. – rekado
¿Qué sucede si cambia la columna a 'binario'? Eso debería sacar la cadena como "8 bits ASCII" (es decir, bytes sin procesar) y tal vez eso pondrá 'YAML.load' en forma. Como prueba rápida, puede 'broken.force_encoding ('binary')' before 'YAML.load (broken)'. –