Ruby生成的JSON与JavaScript的JSON解析器不兼容

时间:2015-04-24 21:04:17

标签: javascript ruby json

我遇到的问题是,当JavaScripts JSON.parse解析时,Ruby脚本生成的JSON不兼容。请考虑以下示例:

# Ruby
require 'json'
hash = {}
hash["key"] = "value with \u001a unicode"
hash.to_json
=> '{"key":"value with \u001a unicode"}'

// JavaScript
JSON.parse('{"key":"value with \u001a unicode"}')
=> JSON.parse: bad control character in string literal at line 1 column 2 of the JSON data

问题是unicode字符\u001a。解决这个问题的方法是将\u001a转义为\\u001a,但事实是,\u001a会被Ruby自动插入到字符串中。我无法可靠地对结果进行后期处理。关于如何解决这个问题的任何想法?

请注意,我希望在JavaScript执行环境中调用JSON.parse,而不是在Ruby的解释器中。

3 个答案:

答案 0 :(得分:2)

简短版本是您在尝试将其解码为JSON之前将字符串解释为Javascript表达式。

U + 001A是一个控制角色。 RFC 4627 explicitly disallows control characters U+0000-U+001F in quoted strings。这里的问题不是JSON无效,而是在尝试将它们解析为JSON之前,你是在取消控制字符。

当您从Ruby转储字符串"\u001a"并将其复制并粘贴到Javascript解释器中时,转义序列将转换为未转义的控制字符,该字符不是JSON中的有效字符!非禁止字符可以正常工作 - 例如,您可以愉快JSON.parse('["\u0020"]')

但是,如果将字符串解释为Javascript,而是将其作为原始字节读取,则会正确解析。

$ irb
irb(main):001:0> require 'json'
=> true
irb(main):003:0> open("out.json", "w") {|f| f.print JSON.dump(["\u001a"]) }
=> nil

$ node -e 'require("fs").readFile("out.json", function(err, data) { console.log(JSON.parse(data)); });'
[ '\u001a' ]

如果您要复制粘贴,则需要复制字符串的转义版本,这样当您的Javascript引擎解析字符串时,转义符双重转义序列正确地转换为逃避序列而不是字符。因此,您应该复制JSON.dump(["\u001a"])的输出,而不是复制puts JSON.dump(["\u001a"]).inspect的输出,这将正确地转义字符串中的任何转义序列。

答案 1 :(得分:0)

对我来说,遵循ruby代码会给"{\"key\":\"value with \\u001a unicode\"}"  在输出中。

JSON.parse也可以通过它。并给出Object {key: "value with unicode"}

答案 2 :(得分:0)

According to the RFC:

JSON text is encoded in unicode. The default unicode is utf-8.

I ran your code in irb and got the following:

1.9.3-p484 :001 > require 'json'
 => true
1.9.3-p484 :002 >
1.9.3-p484 :003 >   hash = {}
 => {}
1.9.3-p484 :004 > hash["key"] = "value with \u001a unicode"
 => "value with \u001A unicode"
1.9.3-p484 :005 > hash.to_json
 => "{\"key\":\"value with \\u001a unicode\"}"

Then running the returned string in a javascript console, I get the following:

> JSON.parse("{\"key\":\"value with \\u001a unicode\"}")
> Object {key: "value with  unicode"}

It is returning an object. To get the value with unicode, you have to access the hash by calling:

> str = JSON.parse("{\"key\":\"value with \\u001a unicode\"}")
> Object {key: "value with  unicode"}
> str.key
> "value with  unicode"