ruby 不使用带引号的键解析JSON

de90aj5v  于 2023-03-12  发布在  Ruby
关注(0)|答案(7)|浏览(120)

我知道在JSON中,键应该用双引号括起来。但是,我使用的数据源没有用引号括起来,这会导致Ruby JSON解析器引发错误。有没有办法执行“非严格”解析?
示例:

>> JSON.parse('{name:"hello", age:"23"}')
JSON::ParserError: 618: unexpected token at '{name:"hello", age:"23"}'
    from /Library/Ruby/Gems/1.8/gems/json-1.1.7/lib/json/common.rb:122:in `parse' 
    from /Library/Ruby/Gems/1.8/gems/json-1.1.7/lib/json/common.rb:122:in `parse'
    from (irb):5
>> JSON.parse('{"name":"hello", "age":"23"}')
=> {"name"=>"hello", "age"=>"23"}
>>

(我尝试在解析之前使用正则表达式添加引号,但无法使其完全工作)。

8hhllhi2

8hhllhi21#

如果除此之外数据的格式非常好,一个简单的正则表达式就可以做到:

irb(main):009:0> '{name:"hello", age:"23"}'.gsub(/([a-z]+):/, '"\1":')
=> "{\"name\":\"hello\", \"age\":\"23\"}"
4urapxun

4urapxun2#

我在第三方数据源上也遇到了同样的问题,但我的数据源返回了一个更复杂的JSON响应,gsub解决方案无法处理。经过一些研究,这些数据源实际上是JavaScript对象文本,不需要引用键。
为了解决这个问题,我添加了execjs gem并安装了node.js(therubyracer gem可能也能正常工作)。完成后,下面的代码返回一个正确解析的ruby散列。

ExecJS.eval('{name:"hello", age:"23"}')
 => {"name"=>"hello", "age"=>"23"}
mqkwyuun

mqkwyuun3#

有趣的是,你的例子是有效的ruby 1.9 Hash语法,如果你的数据真的像这样简单(键名中没有空格或其他特殊字符),并且你可以在一个安全的上下文中处理它,你可以直接eval它。

irb(main):001:0> eval '{name:"hello", age:"23"}'
=> {:name=>"hello", :age=>"23"}

这会将符号作为键,因此如果需要将它们转换为字符串,请进行后处理:

irb(main):002:0> eval('{name:"hello", age:"23"}').reduce({}) {|h,(k,v)| h[k.to_s] = v; h}
=> {"name"=>"hello", "age"=>"23"}
jgzswidk

jgzswidk4#

gsub(/(\w+)\s*:/, '"\1":')

效果比

gsub(/([a-z]+):/, '"\1":')

如果有空格或大写字母,则失败。

x7rlezfr

x7rlezfr5#

(回答我自己的问题)弗洛伊德发布的代码片段和我尝试的很相似--它失败了,因为我的一些字符串包含冒号,但我坚持了下来,并找到了一个解决方案:

gsub(/([\{|\,}])\s*([a-zA-Z]+):/, '\1 "\2":')
20jt8wwn

20jt8wwn6#

这就是我不得不解决它的方法:

JSON.parse(broken_json_string.gsub(/'([^']+)':/, '"\1":'))

上面的一些假设键只包含字母;我们的一些字符串包含下划线、空格等。简单地说“不是单引号的任何字符”(在我们的例子中,所有的键都用单引号括起来)。

bxjv4tth

bxjv4tth7#

实际上你可以使用一个YAML解析器,因为YAML基本上是JSON,没有使用qoutes作为键(尽管它也允许这样做)。但是它不喜欢冒号后面没有空格(否则就把它看作一个字符串)。但是我认为它仍然比试图把qoutes放在任意字符串周围的正则表达式更健壮
所以这应该行得通:

require 'yaml'

s = '{name:"hello", age:"23"}'
YAML.load(s.gsub(':', ': '))

这也很好地将类型转换为ruby类型(就像整数转换为数字),允许单引号和双引号转换为字符串等。
例如一个这个

YAML.load("{ integer: 123, boolean: false, float: 123.4, string: 'Hello', another_string: \"Double quotes\", array: ['str'] }")

退货

{"integer"=>123, "boolean"=>false, "float"=>123.4, "string"=>"Hello", "another_string"=>"Double quotes", "array"=>["str"]}

因此,它几乎和使用eval一样方便,而且没有使用eval带来的所有安全缺陷。

相关问题