Ho appena aggiornato da Ruby 1.9.2 a Ruby 1.9.3p0 (revisione 2011-10-30 33570). L'applicazione My Rails utilizza postgresql come database back-end. Le impostazioni internazionali del sistema sono UTF8, così come la codifica del database. Anche la codifica predefinita dell'applicazione rails è UTF8. Ho utenti cinesi che inseriscono caratteri cinesi e caratteri inglesi. Le stringhe sono memorizzate come stringhe codificate UTF8. VersioneRails: problemi di codifica con gli hash serializzati nonostante UTF8
Rails: 3.0.9
Dal momento che l'aggiornamento alcune delle stringhe cinesi esistenti nel database non sono più visualizzate correttamente. Questo non ha effetto su tutte le stringhe, ma solo su quelle che fanno parte di un hash serializzato. Tutte le altre stringhe memorizzate come semplici stringhe sembrano ancora corrette.
Esempio:
Questo è un hash serializzata che viene memorizzato come una stringa UTF8 nel database:
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"
Al fine di convertire questa stringa per un hash rubino, ho deserializzare con YAML.load
:
broken_hash = YAML.load(broken)
Questo restituisce un hash con contenuti incomprensibili:
{"checkbox"=>"1", "choice"=>"Round Paper Clips ï¼\u0088å\u009B\u009Eå½¢é\u0092\u0088ï¼\u0089\r\n", "info"=>"10ç\u009B\u0092"}
si suppone La roba incomprensibile per essere UTF8-encoded cinese. broken_hash['info'].encoding
mi dice che Ruby pensa che questo sia #<Encoding:UTF-8>
. Non sono d'accordo.
È interessante notare che tutte le altre stringhe che non sono state serializzate prima sembrano comunque soddisfacenti. Nello stesso record un campo diverso contiene caratteri cinesi che sembrano giusti --- nella console di rails, nella console psql e nel browser. Ogni stringa --- non importa se hash serializzato o stringa semplice --- salvati nel database poiché anche l'aggiornamento sembra soddisfacente.
ho cercato di convertire il testo confuso da un possibile codifica sbagliata (come GB2312 o ANSI) a UTF-8, nonostante l'affermazione di ruby che questa era già UTF-8 e, naturalmente, ho fallito. Questo è il codice che ho usato:
require 'iconv'
Iconv.conv('UTF-8', 'GB2312', broken_hash['info'])
Questo fallisce perché rubino non sa cosa fare con le sequenze illegali nella stringa.
In realtà voglio solo eseguire uno script per correggere tutte le stringhe hash seriamente cancellate, presumibilmente interrotte, e utilizzarle. C'è un modo per convertire queste stringhe spezzate in qualcosa che assomiglia di nuovo al cinese?
me a con la stringa codificata UTF-8 nella stringa grezzo (chiamati "spezzato" nell'esempio precedente). Questa è la stringa cinese che è codificato nella stringa serializzata:
chinese = "\\xEF\\xBC\\x88\\xE5\\x9B\\x9E\\xE5\\xBD\\xA2\\xE9\\x92\\x88\\xEF\\xBC\\x89\\r\\n\"
ho notato che è facile da convertire ad un vero e proprio UTF-8 stringa codificata da unescaping esso (rimuovere le barre inverse di fuga).
chinese_ok = "\xEF\xBC\x88\xE5\x9B\x9E\xE5\xBD\xA2\xE9\x92\x88\xEF\xBC\x89\r\n"
Questo restituisce una corretta UTF-8-encoded stringa cinese: "(回形针)\r\n"
La cosa cade a pezzi solo quando uso YAML.load(...)
per convertire la stringa in un hash rubino. Forse dovrei elaborare la stringa non elaborata prima che venga inviata a YAML.load
. Mi fa solo chiedere perché è così ...
Interessante! Questo è probabilmente dovuto al motore "psicologico" YAML che è usato di default ora nella 1.9.3. Sono passato al motore "syck" con e le stringhe rotte sono state analizzate correttamente.
Qual è il tipo di colonna per gli hash serializzati? –
@muistooshort: il tipo di colonna è 'testo'. – rekado
Cosa succede se cambi la colonna in 'binary'? Dovrebbe ottenere la stringa come "8bit ASCII" (cioè i byte grezzi) e forse questo darà un calcio a "YAML.load" in forma. Come test rapido puoi 'broken.force_encoding ('binary')' prima 'YAML.load (broken)'. –