Parsing JSON without quoted keys

Viewed 13789

I understand that in JSON, keys are supposed to be surrounded in double quotes. However, I'm using a data source which doesn't quote them, which is causing the Ruby JSON parser to raise an error. Is there any way to perform 'non-strict' parsing?

Example:

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

(I tried using a regular expression to add the quotes in before parsing but couldn't get it fully working).

6 Answers

If the data is pretty well formed other than that, a simple regex might do it:

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

Interestingly, your example is valid ruby 1.9 Hash syntax. If your data is really as simple as this (no spaces or other special characters in the key names), and you can process it in a safe context, you can just eval it.

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

This gives you symbols as keys, so post-process if you need to turn them into strings:

irb(main):002:0> eval('{name:"hello", age:"23"}').reduce({}) {|h,(k,v)| h[k.to_s] = v; h}
=> {"name"=>"hello", "age"=>"23"}
gsub(/(\w+)\s*:/, '"\1":')

worked better than

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

If it had spaces or capital letters, it failed.

(Answering my own question) The snippet that floyd posted was similar to what I tried - it was failing because some of my strings contain colons. But I persisted and found a solution:

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