How to parse a string representation of a hash

28,772

Solution 1

Guess I never posted my workaround for this... Here it goes,

# strip the hash down
stringy_hash = "account_id=>4444, deposit_id=>3333"

# turn string into hash
Hash[stringy_hash.split(",").collect{|x| x.strip.split("=>")}]

Solution 2

The way suggested in miku's answer is indeed easiest and unsafest.

# DO NOT RUN IT
eval '{:surprise => "#{system \"rm -rf / \"}"}'
# SERIOUSLY, DON'T

Consider using a different string representation of your hashes, e.g. JSON or YAML. It's way more secure and at least equally robust.

Solution 3

With a little replacement, you may use YAML:

require 'yaml'

p YAML.load(
  "{:account_id=>4444, :deposit_id=>3333}".gsub(/=>/, ': ')
  )

But this works only for this specific, simple string. Depending on your real data you may get problems.

Solution 4

if your string hash is some sort of like this (it can be nested or plain hash)

stringify_hash = "{'account_id'=>4444, 'deposit_id'=>3333, 'nested_key'=>{'key1' => val1, 'key2' => val2, 'key3' => nil}}"

you can convert it into hash like this without using eval which is dangerous

desired_hash = JSON.parse(stringify_hash.gsub("'",'"').gsub('=>',':').gsub('nil','null'))

and for the one you posted where the key is a symbol you can use like this

JSON.parse(string_hash.gsub(':','"').gsub('=>','":'))

Solution 5

The easiest and unsafest would be to just evaluate the string:

>> s = "{:account_id=>4444, :deposit_id=>3333}"
>> h = eval(s)
=> {:account_id=>4444, :deposit_id=>3333}
>> h.class
=> Hash
Share:
28,772
zoras
Author by

zoras

Updated on December 16, 2021

Comments

  • zoras
    zoras over 2 years

    I have this string and I'm wondering how to convert it to a Hash.

    "{:account_id=>4444, :deposit_id=>3333}"
    
  • zoras
    zoras over 12 years
    I'm getting these in rails post params. Isn't there a safe way to convert string into hash other than eval.
  • zoras
    zoras over 12 years
    nop these are rails post params so i guess i can't use json or yaml
  • Jan
    Jan over 12 years
    Interesting. Controllers in Rails usually receive POST params as Ruby objects. How come you get them as a string?
  • miku
    miku over 12 years
    I don't know your setup, but maybe it would be easier to get back a hash in the first place. Otherwise, ruby supports some TAINT levels, see: ruby-doc.org/docs/ProgrammingRuby/html/taint.html
  • Pavling
    Pavling over 12 years
    lets hope no one runs that to "see what it will do" :-/
  • Jan
    Jan over 12 years
    @Pavling, good point. I've added an appropriate piece of advice.
  • zoras
    zoras over 12 years
    Actually, I'm sending these as custom options for paypal like this :custom => {:account_id => @account.id, :deposit_id => @deposit.id}. So, when paypal posts back the IPN the hash is quoted as string in the controller. Is there any other way to send multiple variables with paypal custom options altogether?
  • Jan
    Jan over 12 years
    @zoras, I guess it's a candidate for a new question with a paypal tag.
  • nurettin
    nurettin over 10 years
    this takes really long when I run it
  • Matt
    Matt almost 10 years
    This will fail to split fields correctly if you have any data that contains a , or =>. { :text => "Welcome, friends.", delim => "=>" }
  • Luca Spiller
    Luca Spiller over 9 years
    Hashes contain 'null' for null objects, where as this contains 'nil', so that would need to be replaced too.
  • volx757
    volx757 over 8 years
    yeah maybe at least explain what the code you wrote does. i feel like it's v possible someone new to ruby/coding might run it anyway just to see. so for that person: it would delete all of your files.
  • Chris Suszyński
    Chris Suszyński about 8 years
    You should add --no-preserve-root to your example to really kick balls! :-P
  • Josh
    Josh over 7 years
    Worked like a charm! I passed mine into HashWithIndifferentAccess.new to get a hash like the param hash.
  • Michael
    Michael over 6 years
    don't forget to add sudo before system
  • Hosam Aly
    Hosam Aly over 2 years
    This would only work with data types that are native to YAML. A regular expression, for example, wouldn't be parseable in this way.