2013-08-05 9 views
8

Podczas próby przekonwertowania skrótu na ciąg json wystąpił błąd JSON::GeneratorError: source sequence is illegal/malformed utf-8. Zastanawiam się, czy to ma coś wspólnego z kodowaniem, i jak mogę zrobić, aby to_json traktował \ xAE tak jak jest?Problem z Ruby to_json z błędem "nielegalne/zniekształcone utf-8"

$ 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

na wszelki wypadek, jeśli masz na myśli "potraktuj to tak, jak jest", możesz dwukrotnie uciec przed nim: {"description" => "iPhone \\ xAE"}. To_json => "{\" description \ ": \ "iPhone \\\\ xAE \"} " –

Odpowiedz

13

\xAE nie jest ważna postać w UTF-8, trzeba użyć \u00AE zamiast:

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

lub przekonwertować je odpowiednio:

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

Każdy ciąg w Ruby ma underlaying encoding. W zależności od zmiennych środowiskowych LANG i LC_ALL, interaktywna powłoka może wykonywać i interpretować łańcuchy w danym kodowaniu.

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

(zignorować, że używam Ruby 1.9 zamiast 2.0, pomysły są nadal takie same).

__ENCODING__ zwraca bieżące kodowanie źródła. Najprawdopodobniej Twój kod będzie również oznaczony jako UTF-8.

Podczas tworzenia dosłowne ciągi i ucieka użycie bajt (The \xAE) w kodzie, Ruby próbuje tłumaczyć, że zgodnie z kodowaniem strun:

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

Więc bajt \xAE na końcu ciąg literowy będzie próbował być traktowany jako bajt strumienia UTF-8, ale jest nieważny. Zobacz, co się dzieje, gdy próbuję go wydrukować:

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

albo trzeba zapewnić zarejestrowanemu znakowi charakter w poprawnym kodowaniem UTF-8 (przy użyciu prawdziwego charakteru lub dostarczenie dwóch bajtów 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®\"}" 

Lub, jeśli wejście jest ISO-8859-1 (Latin 1) i wiesz, to na pewno można powiedzieć Ruby interpretować swój ciąg jako innym kodowaniu:

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

nadzieję, że pomaga.

+0

Wielkie dzięki za jasne wyjaśnienie. Nie zauważyłem, że \ xAE nie był kodowany w UTF-8, ale korzystał z kodu JavaScript escape (http://www.charbase.com/00ae-unicode-registered-sign) – ccy