2013-08-05 13 views
8

Ho ricevuto un errore JSON::GeneratorError: source sequence is illegal/malformed utf-8 durante il tentativo di convertire un hash in stringa json. Mi chiedo se questo abbia qualcosa a che fare con la codifica, e come posso rendere to_json solo trattare \ xAE così com'è?Ruby to_json problema con errore "utf-8 illegale/non valido"

$ 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>' 
+0

nel caso in cui intendiate 'trattatelo così com'è', potreste evitarlo due volte: {"description" => "iPhone \\ xAE"}. To_json => "{\" description \ ": \ "iPhone \\\\ xAE \"} " –

risposta

13

\xAE non è un carattere valido in UTF-8, è necessario utilizzare \u00AE invece:

"iPhone\u00AE" 
#=> "iPhone®" 

O convertirlo conseguenza:

"iPhone\xAE".force_encoding("ISO-8859-1").encode("UTF-8") 
#=> "iPhone®" 
13

Ogni stringa in Ruby ha un underlaying encoding. A seconda delle variabili di ambiente LANG e LC_ALL, la shell interattiva potrebbe eseguire e interpretare le stringhe in una determinata codifica.

$ irb 
1.9.3p392 :008 > __ENCODING__ 
=> #<Encoding:UTF-8> 

(ignoro che sto usando Ruby 1.9 invece di 2.0, le idee sono sempre gli stessi).

__ENCODING__ restituisce la codifica sorgente corrente. Il tuo probabilmente dirà anche UTF-8.

Quando si creano le stringhe letterali e fughe uso di byte (la \xAE) nel codice, Ruby sta cercando di interpretare che secondo la codifica stringa:

1.9.3p392 :003 > a = {"description" => "iPhone\xAE"} 
=> {"description"=>"iPhone\xAE"} 
1.9.3p392 :004 > a["description"].encoding 
=> #<Encoding:UTF-8> 

Così, il byte \xAE alla fine del tuo la stringa letterale verrà tentata di essere trattata come un byte di flusso UTF-8, ma non è valida. Vedi cosa succede quando si tenta di stampare:

1.9.3-p392 :001 > puts "iPhone\xAE" 
iPhone� 
=> nil 

Si sia necessario fornire il carattere di marchio registrato in una codifica UTF-8 valida (sia utilizzando il carattere reale, o fornendo i due byte 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, se l'input è ISO-8859-1 (Latin 1) e tu lo sai per certo, si può dire di Ruby di interpretare la stringa come un altro di codifica:

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®\"}" 

spero che aiuta.

+0

Grazie mille per la spiegazione chiara. Non ho notato che \ xAE non era codificato in UTF-8 ma utilizzava JavaScript escape (http://www.charbase.com/00ae-unicode-registered-sign) – ccy

Problemi correlati