Ruby to_json problema con el error "ilegal/malformado utf-8"
encoding ruby (2)
Obtuve un error JSON::GeneratorError: source sequence is illegal/malformed utf-8
cuando se intenta convertir un hash en cadena json. Me pregunto si esto tiene algo que ver con la codificación, y ¿cómo puedo hacer que to_json simplemente trate / xAE tal como es?
$ irb
2.0.0-p247 :001 > require ''json''
=> true
2.0.0-p247 :002 > a = {"description"=> "iPhone/xAE"}
=> {"description"=>"iPhone/xAE"}
2.0.0-p247 :003 > a.to_json
JSON::GeneratorError: source sequence is illegal/malformed utf-8
from (irb):3:in `to_json''
from (irb):3
from /Users/cchen21/.rvm/rubies/ruby-2.0.0-p247/bin/irb:16:in `<main>''
Cada cadena en Ruby tiene una codificación subyacente. Dependiendo de las variables de entorno LANG
y LC_ALL
, el shell interactivo podría estar ejecutando e interpretando sus cadenas en una codificación determinada.
$ irb
1.9.3p392 :008 > __ENCODING__
=> #<Encoding:UTF-8>
(Ignore que estoy usando Ruby 1.9 en lugar de 2.0, las ideas siguen siendo las mismas).
__ENCODING__
devuelve la codificación fuente actual. El tuyo probablemente también diga UTF-8.
Cuando crea cadenas literales y usa escapes de bytes (el /xAE
) en su código, Ruby intenta interpretar eso de acuerdo con la codificación de cadena:
1.9.3p392 :003 > a = {"description" => "iPhone/xAE"}
=> {"description"=>"iPhone/xAE"}
1.9.3p392 :004 > a["description"].encoding
=> #<Encoding:UTF-8>
Por lo tanto, se intentará tratar el byte /xAE
al final de su cadena literal como un byte de secuencia UTF-8, pero no es válido. Vea lo que sucede cuando intento imprimirlo:
1.9.3-p392 :001 > puts "iPhone/xAE"
iPhone�
=> nil
Debe proporcionar el carácter de marca registrada en una codificación UTF-8 válida (ya sea utilizando el carácter real o proporcionando los dos bytes UTF-8):
1.9.3-p392 :002 > a = {"description1" => "iPhone®", "description2" => "iPhone/xc2/xae"}
=> {"description1"=>"iPhone®", "description2"=>"iPhone®"}
1.9.3-p392 :005 > a.to_json
=> "{/"description1/":/"iPhone®/",/"description2/":/"iPhone®/"}"
O bien, si su entrada es ISO-8859-1 (Latin 1) y lo sabe con certeza, puede decirle a Ruby que interprete su cadena como otra codificación:
1.9.3-p392 :006 > a = {"description1" => "iPhone/xAE".force_encoding(''ISO-8859-1'') }
=> {"description1"=>"iPhone/xAE"}
1.9.3-p392 :007 > a.to_json
=> "{/"description1/":/"iPhone®/"}"
Espero eso ayude.
/xAE
no es un carácter válido en UTF-8, en su lugar debe usar /u00AE
:
"iPhone/u00AE"
#=> "iPhone®"
O conviértalo en consecuencia:
"iPhone/xAE".force_encoding("ISO-8859-1").encode("UTF-8")
#=> "iPhone®"