2016-06-23 17 views
8

Mam problem ze znakami specjalnymi podczas przesyłania skrótu do łańcucha json.to_json nie konwertuje znaków specjalnych na styl Unicode

Wszystko działa poprawnie z Ruby 2.0/Rails 3.2.21, to znaczy

puts "“".to_json 
#"\u201c" 

Ale z Ruby 2.3.0/Rails 4.2.5.1 uzyskać

puts "“".to_json 
#"“" 

Czy istnieje jakiś sposób, zmusić Ruby 2.3.0 do konwersji znaków specjalnych na ciągi w stylu Unicode (\uXXXX)?

Uwaga:

Zauważ, że w Ruby 2.3/Szyny 4, otrzymujemy

"“".to_json.bytesize == 5 #true 

Jednak w 2,0 otrzymujemy

"“".to_json.bytesize == 8 #true 

Tak wyraźnie to sam ciąg znaków, który jest inny , nie różne formaty wyjściowe.

+1

Porównujesz 'puts' implementację różnych wersji ruby. Czy mógłbyś wyjaśnić, jaki jest prawdziwy problem, który próbujesz rozwiązać? – mudasobwa

+0

Porównuję co? To nie ma nic wspólnego z różnymi implementacjami putów. Zobacz "" ".to_json.bytesize == 5 dla 2.3, ale" "" .to_json.bytesize == 8 dla 2.0 – Ingo

Odpowiedz

5

I ❤ poręcze (tylko żartowałem.)

W Rails3 było hilarious method uszkodzić UTF-8 w JSON. Rails4, dzięki DHH, uwolniony od tej wady.

Więc, czy ktoś chce maszynę czasu wstecz, najprostszym sposobem jest monkeypatch ::ActiveSupport::JSON::Encoding#escape:

module ::ActiveSupport::JSON::Encoding 
    def self.escape(string) 
    if string.respond_to?(:force_encoding) 
     string = string.encode(::Encoding::UTF_8, :undef => :replace) 
        .force_encoding(::Encoding::BINARY) 
    end 
    json = string. 
      gsub(escape_regex) { |s| ESCAPED_CHARS[s] }. 
      gsub(/([\xC0-\xDF][\x80-\xBF]| 
        [\xE0-\xEF][\x80-\xBF]{2}| 
        [\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s| 
      s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\\\u\&') 
      } 
    json = %("#{json}") 
    json.force_encoding(::Encoding::UTF_8) if json.respond_to?(:force_encoding) 
    json 
    end 
end 

Bardziej niezawodne rozwiązanie byłoby zepsutego Rezultat:

class String 
    def rails3_style 
    string = encode(::Encoding::UTF_8, :undef => :replace). 
       force_encoding(::Encoding::BINARY) 
    json = string. 
     gsub(/([\xC0-\xDF][\x80-\xBF]| 
      [\xE0-\xEF][\x80-\xBF]{2}| 
      [\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s| 
     s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\\\u\&') 
    } 
    json = %("#{json}") 
    json.force_encoding(::Encoding::UTF_8) if json.respond_to?(:force_encoding) 
    json 
    end 
end 

puts "“".to_json.rails3_style 
#⇒ "\u201c" 

Ledwo mogłem zrozumieć, dlaczego ktokolwiek może chcieć zrobić to celowo, ale rozwiązanie jest tutaj.

Powiązane problemy