Consider the following code:
hash1 = {\"one\" => 1, \"two\" => 2, \"three\" => 3}
hash2 = hash1.reduce({}){ |h, (k,v)| h.merge(k => hash1) }
ha
You could use:
This is an easy solution to your problem, but, you should only consider using it if you can trust that eval
is not going to produce something nasty. If you have control over the content of the hash being converted, that should not be a problem.
This approach could be used for other kinds of nested objects, such as ones containing both arrays and hashes.
Code
def symbolize_hash(h)
eval(h.to_s.gsub(/\"(\w+)\"(?==>)/, ':\1'))
end
Examples
symbolize_hash(hash4)
#=> {:one=>{:one=> {:one=> {:one=>1, :two=>2, :three=>3},
# :two=> {:one=>1, :two=>2, :three=>3},
# :three=>{:one=>1, :two=>2, :three=>3}},
# :two=> {:one=> {:one=>1, :two=>2, :three=>3},
# :two=> {:one=>1, :two=>2, :three=>3},
# :three=>{:one=>1, :two=>2, :three=>3}},
# :three=>{:one=> {:one=>1, :two=>2, :three=>3},
# :two=> {:one=>1, :two=>2, :three=>3},
# :three=>{:one=>1, :two=>2, :three=>3}}},
# :two=>{:one=> {:one=> {:one=>1, :two=>2, :three=>3},
# ...
# :three=>{:one=>{:one=> {:one=>1, :two=>2, :three=>3},
# ...
# :three=>{:one=>1, :two=>2, :three=>3}}}}
symbolize_hash({'a'=>1, 'b'=>[{'c'=>{'d'=>'d'}}, {e:'f'}]})
#=> {:a=>1, :b=>[{:c=>{:d=>"d"}}, {:e=>"f"}]}
Explanation
(?==>)
in the regex is a zero-width postive lookahead. ?=
signifies positive lookahead; =>
is the string that must immediately follow the match to \"(\w+)\"
. \1
in ':\1'
(or I could have written ":\\1"
) is a string beginning with a colon followed by a backreference to the content of capture group #1, the key matching \w+
(without the quotes).