tags:

views:

480

answers:

4

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).

A: 

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"}
glenn mcdonald
Thanks for that, although since I'm using 1.8.7 that's not an option at the moment.
Andy Waite
+2  A: 

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\"}"
floyd
A: 

(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":')
Andy Waite
+1  A: 

gsub(/(\w+)\s*:/, '"\1":') worked better for me than gsub(/([a-z]+):/, '"\1":')

If it had spaces or capital letters, it failed.

Samsinite