[Solved] Regular expression to split ruby strings into multiple hashes

[ad_1]

It looks like you tried to create your own JSON serializer, instead of using the one that comes with Ruby. Or, perhaps you didn’t realize that JSON was a thing and wanted to store arrays of hashes and tried to invent your own. Either way, it wasn’t a good path to follow.

This is your definition, which, after being retrieved would remain a String. It appears to be the elements of an Array of Hashes, without the surrounding Array [ and ]:

foo = "{\"monday\"=>\"{:start_time=>9.0, :end_time=>10.5}\"},{\"tuesday\"=>\"{:start_time=>8.5, :end_time=>10.0}\"},{\"wednesday\"=>\"{:start_time=>8.5, :end_time=>10.0}\"}"

and it remains a String:

foo.class # => String

It’d be possible to munge it back into a form that could be evaluated and turned back into an Array of Hashes, but it’s not straightforward, nor is it clean or convenient or elegant.

I suspect your original object looked like this:

foo = {"monday"=>{:start_time=>9.0, :end_time=>10.5}},{"tuesday"=>{:start_time=>8.5, :end_time=>10.0}},{"wednesday"=>{:start_time=>8.5, :end_time=>10.0}}
# => [{"monday"=>{:start_time=>9.0, :end_time=>10.5}},
#     {"tuesday"=>{:start_time=>8.5, :end_time=>10.0}},
#     {"wednesday"=>{:start_time=>8.5, :end_time=>10.0}}]

which is an Array:

foo.class # => Array

It’s an Array now because you have multiple Hash elements separated by commas (,) which Ruby interprets as an Array when assigned to a single variable. This would be a less visually confusing example:

foo = {a: 1}, {a: 2} # => [{:a=>1}, {:a=>2}]
foo.class  # => Array
foo.first.class # => Hash

Back to the Array of Hashes in foo: Starting from that it’s easy to let the JSON class serialize it into a string that can be stored in a database, then retrieved and reparsed back into a Ruby object:

require 'json'
foo.to_json

foo.to_json would result in a serialized string that looks like:

[{"monday":{"start_time":9.0,"end_time":10.5}},{"tuesday":{"start_time":8.5,"end_time":10.0}},{"wednesday":{"start_time":8.5,"end_time":10.0}}]

And, given that string, JSON can rebuild the object:

bar = JSON.parse(foo.to_json)
# => [{"monday"=>{"start_time"=>9.0, "end_time"=>10.5}},
#     {"tuesday"=>{"start_time"=>8.5, "end_time"=>10.0}},
#     {"wednesday"=>{"start_time"=>8.5, "end_time"=>10.0}}]

Note that it’s not necessary to use parse or to_json. The class is smart enough to recognize whether the parameter is a String, or an Array or Hash, and parse or serialize respectively:

JSON[JSON[foo]]
# => [{"monday"=>{"start_time"=>9.0, "end_time"=>10.5}},
#     {"tuesday"=>{"start_time"=>8.5, "end_time"=>10.0}},
#     {"wednesday"=>{"start_time"=>8.5, "end_time"=>10.0}}]

At this point you’re prepared to store the values into a String-type field in your database, then retrieve them later and reuse them.

If you are hoping to search or manipulate those stored JSON strings, I’d recommend re-thinking that. While a modern DBM can search inside JSON and generate it, you’d be better off having a separate table of the keys and values. It’s faster and more flexible.

Finally to your question, how to convert the string so you can get the keys and values:

foo = "{\"monday\"=>\"{:start_time=>9.0, :end_time=>10.5}\"},{\"tuesday\"=>\"{:start_time=>8.5, :end_time=>10.0}\"},{\"wednesday\"=>\"{:start_time=>8.5, :end_time=>10.0}\"}"
bar = eval('[' + foo.gsub(/"([{}])/, '\1') + ']')
bar
# => [{"monday"=>{:start_time=>9.0, :end_time=>10.5}},
#     {"tuesday"=>{:start_time=>8.5, :end_time=>10.0}},
#     {"wednesday"=>{:start_time=>8.5, :end_time=>10.0}}]

bar.map { |h| [h.keys, h.values.first.keys] }
# => [[["monday"], [:start_time, :end_time]],
#     [["tuesday"], [:start_time, :end_time]],
#     [["wednesday"], [:start_time, :end_time]]]

This hints that the Array of Hashes wasn’t the right structure either. A simple hash would have sufficed:

foo = {
  "monday"=>{:start_time=>9.0, :end_time=>10.5},
  "tuesday"=>{:start_time=>8.5, :end_time=>10.0},
  "wednesday"=>{:start_time=>8.5, :end_time=>10.0}
}

require 'json'
bar = JSON[JSON[foo]] # imitate a round-trip to/from the DB
bar.keys # => ["monday", "tuesday", "wednesday"]
bar.values # => [{"start_time"=>9.0, "end_time"=>10.5}, {"start_time"=>8.5, "end_time"=>10.0}, {"start_time"=>8.5, "end_time"=>10.0}]

1

[ad_2]

solved Regular expression to split ruby strings into multiple hashes