2016-06-23 18 views
8

Tôi gặp sự cố với các ký tự đặc biệt khi truyền một hàm băm vào chuỗi json.to_json không chuyển đổi các ký tự đặc biệt thành kiểu unicode

Tất cả mọi thứ hoạt động tốt với Ruby 2.0/Rails 3.2.21, có nghĩa là,

puts "“".to_json 
#"\u201c" 

Nhưng với Ruby 2.3.0/Rails 4.2.5.1 tôi nhận được

puts "“".to_json 
#"“" 

Có cách nào để buộc Ruby 2.3.0 chuyển đổi các ký tự đặc biệt thành các chuỗi kiểu unicode (\uXXXX)?

Ghi chú:

Chú ý rằng trong Ruby 2.3/Rails 4, chúng tôi nhận

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

Tuy nhiên, trong 2.0 chúng tôi nhận

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

Vì vậy, rõ ràng nó chuỗi riêng của mình đó là khác nhau , không phải định dạng đầu ra khác nhau.

+1

Bạn so sánh việc thực hiện 'puts' các phiên bản ruby ​​khác nhau. Bạn có muốn giải thích vấn đề thực sự bạn đang cố gắng giải quyết không? – mudasobwa

+0

Tôi so sánh cái gì? Điều này không liên quan gì đến các triển khai đặt khác nhau. Xem "" ".to_json.bytesize == 5 cho 2.3 nhưng" "" .to_json.bytesize == 8 cho 2.0 – Ingo

Trả lời

5

tôi ❤ Rails (chỉ đùa thôi.)

Trong Rails3 có một hilarious method làm hỏng UTF-8 trong JSON. Rails4, cảm ơn DHH, giải thoát khỏi nhược điểm này.

Vì vậy, cho dù ai muốn những cỗ máy thời gian trở lại, cách đơn giản nhất là 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 

giải pháp mạnh mẽ hơn sẽ được tham nhũng kết quả:

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" 

Tôi hầu như không thể hiểu tại sao ai đó có thể muốn làm điều này có chủ đích, nhưng giải pháp là ở đây.

Các vấn đề liên quan