16

JSON::GeneratorError: source sequence is illegal/malformed utf-8尝试将哈希转换为 json 字符串时出现错误。我想知道这是否与编码有关,我怎样才能让 to_json 按原样对待 \xAE?

$ 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>'
4

2 回答 2

24

\xAE不是 UTF-8 中的有效字符,您必须\u00AE改用:

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

或相应地转换它:

"iPhone\xAE".force_encoding("ISO-8859-1").encode("UTF-8")
#=> "iPhone®"
于 2013-08-05T21:00:12.897 回答
20

Ruby 中的每个字符串都有一个底层编码。根据您LANGLC_ALL环境变量,交互式 shell 可能会以给定的编码执行和解释您的字符串。

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

(忽略我使用的是 Ruby 1.9 而不是 2.0,想法还是一样的)。

__ENCODING__返回当前的源编码。你的可能也会说 UTF-8。

当您\xAE在代码中创建文字字符串并使用字节转义符 (the) 时,Ruby 会尝试根据字符串编码对其进行解释:

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

因此,\xAE将尝试将文字字符串末尾的字节视为 UTF-8 流字节,但它是无效的。看看当我尝试打印它时会发生什么:

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

您需要以有效的 UTF-8 编码提供已注册的标记字符(使用真实字符或提供两个 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®\"}"

或者,如果您的输入是 ISO-8859-1 (Latin 1) 并且您肯定知道,您可以告诉 Ruby 将您的字符串解释为另一种编码:

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

希望能帮助到你。

于 2013-08-05T21:02:19.857 回答