Alex Sid
Alex Sid

Reputation: 148

How to parse single-string array to hash in Ruby?

I have a Ruby array (don't ask me why it is not hash already, i can't do anything about it):

[{":cost=>100", ":size=>2"}]

What do i need to do to make it the classical Ruby hash with keys and values? What is my best option? Maybe there is some libraries for this kind of operations?

Thanks.

Upvotes: 2

Views: 229

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110685

You could use the JSON module to do that. That would arguably be safer than by using eval.

To see how JSON could be used, let's do some reverse-engineering. You want to create a hash:

h = { :cost=>100, :size=>2 }

from the string:

str = '[{":cost=>100", ":size=>2"}]'
  #=> "[{\":cost=>100\", \":size=>2\"}]"

Let's see how that hash would be encoded as a JSON string:

require 'json'
jstr = JSON.generate(h)
  #=> "{\"cost\":100,\"size\":2}" 

Once we have jstr (which is nothing more than a string) we can extract the desired hash:

JSON.parse(jstr)
  #=> {"cost"=>100, "size"=>2}

so the task reduces to converting str to jstr:

  "[{\":cost=>100\", \":size=>2\"}]" => "{\"cost\":100,\"size\":2}" 

Perhaps the easiest way is to first pull out the keys and values, which we can do with a regex:

r = /
    (       # start capture group 1
      [a-z] # match a lowercase letter
      \w*   # match >= 0 word characters
    )       # close capture group 1
    =>      # match characters
    (-?\d+) # optionally match a minus sign followed by > 0 digits in
            # capture group 2
    /x      # free-spacing regex definition mode

arr = str.scan r
  #=> [["cost", "100"], ["size", "2"]]

We can now form jstr:

jstr = "{#{ arr.map { |k,v| "\"#{k}\":#{v}" }.join(",") }}" 
  #=> "{\"cost\":100,\"size\":2}"

To confirm,

h = JSON.parse(jstr)
  #=> {"cost"=>100, "size"=>2}

Upvotes: 1

Silver Phoenix
Silver Phoenix

Reputation: 521

First we need to clean the string to make it look like a valid array:

my_string = my_string[2..-3]
my_array = eval("[#{my_string}]")

Now you can join the strings, and then eval it into a hash:

elements = my_array.join(', ')
my_hash = eval("{ #{ elements } }")

(this can be done in fewer lines, but I separated them for clarity)

Upvotes: 1

Related Questions