2

I have this string which I need to convert to to a Hash :

str = '{:gender=>{:content=>"male"}, :names=>[{:first=>"Atair", :last=>"Goron"}], :addresses=>[{:country=>"GB", :state=>"ENG", :city=>"London"}], :emails=>[{:address=>"agoron@keolis.com", :address_md5=>"971b2fd0b83c900a5ca62c91dab80dd9"}, {:address=>"atair.godon.75@facebook.com", :address_md5=>"a0d958c1396300a344356d57b6836f9e"}], :jobs=>[{:title=>"Chief Executive Officer", :organization=>"Kolis UK and Eire"}, {:title=>"Deputy Managing Director", :organization=>"Kolis UK", :date_range=>{:start=>"2008-04-01", :end=>"2010-04-01"}}, {:title=>"Project Director", :organization=>"Keolis UK", :date_range=>{:start=>"2004-04-01", :end=>"2008-04-01"}}, {:title=>"Strategic Planning Director", :organization=>"Eurostar", :date_range=>{:start=>"2002-04-01", :end=>"2004-04-01"}}, {:title=>"Commercial Director, Business Markets", :organization=>"Eurostar", :date_range=>{:start=>"1999-11-01", :end=>"2002-04-01"}}, {:title=>"Brand Manager", :organization=>"Eurostar", :date_range=>{:start=>"1998-06-01", :end=>"1999-11-01"}}, {:title=>"Business Forecasting Manager", :organization=>"Eurostar", :date_range=>{:start=>"1997-08-01", :end=>"1998-06-01"}}, {:title=>"Principal Consultant", :organization=>"Steer Davies Gleave", :date_range=>{:start=>"1995-04-01", :end=>"1997-08-01"}}, {:title=>"Transport Consultant", :organization=>"Sir Alexander Gibb and Part", :date_range=>{:start=>"1990-01-01", :end=>"1995-12-31"}}], :educations=>[{:school=>"U. of London"}, {:school=>"University College London, U. of London", :date_range=>{:start=>"1987-01-01", :end=>"1990-12-31"}}], :usernames=>[{:content=>"alistair.gordon.75"}], :user_ids=>[{:content=>"5/238/746@linkedin"}, {:content=>"538818605@facebook"}, {:content=>"15504678@linkedin"}]}'

I have floating number of keys, each key value can be either a string, array, hash or hash of hashes

Is there way to convert it?

Stefan
  • 109,145
  • 14
  • 143
  • 218
Mikhail Chuprynski
  • 2,404
  • 2
  • 29
  • 42

2 Answers2

11

You could try to convert the format to JSON by replacing :key=> with "key"::

str.gsub!(/:(\w+)=>/, '"\1":')
#=> "{\"gender\":{\"content\":\"male\"}, \"names\":[{\"first\":\"Atair\", ...

And parse it as usual:

require 'json'
JSON.parse(str, symbolize_names: true)
#=> {:gender=>{:content=>"male"}, :names=>[{:first=>"Atair", ...
Stefan
  • 109,145
  • 14
  • 143
  • 218
5

This is dirty way eval : eval Evaluates the Ruby expression(s) in string.

 > s = '{:gender=>{:content=>"male"}, :names=>[{:first=>"Atair", :last=>"Goron"}], :addresses=>[{:country=>"GB", :state=>"ENG", :city=>"London"}], :emails=>[{:address=>"agoron@keolis.com", :address_md5=>"971b2fd0b83c900a5ca62c91dab80dd9"}, {:address=>"atair.godon.75@facebook.com", :address_md5=>"a0d958c1396300a344356d57b6836f9e"}], :jobs=>[{:title=>"Chief Executive Officer", :organization=>"Kolis UK and Eire"}, {:title=>"Deputy Managing Director", :organization=>"Kolis UK", :date_range=>{:start=>"2008-04-01", :end=>"2010-04-01"}}, {:title=>"Project Director", :organization=>"Keolis UK", :date_range=>{:start=>"2004-04-01", :end=>"2008-04-01"}}, {:title=>"Strategic Planning Director", :organization=>"Eurostar", :date_range=>{:start=>"2002-04-01", :end=>"2004-04-01"}}, {:title=>"Commercial Director, Business Markets", :organization=>"Eurostar", :date_range=>{:start=>"1999-11-01", :end=>"2002-04-01"}}, {:title=>"Brand Manager", :organization=>"Eurostar", :date_range=>{:start=>"1998-06-01", :end=>"1999-11-01"}}, {:title=>"Business Forecasting Manager", :organization=>"Eurostar", :date_range=>{:start=>"1997-08-01", :end=>"1998-06-01"}}, {:title=>"Principal Consultant", :organization=>"Steer Davies Gleave", :date_range=>{:start=>"1995-04-01", :end=>"1997-08-01"}}, {:title=>"Transport Consultant", :organization=>"Sir Alexander Gibb and Part", :date_range=>{:start=>"1990-01-01", :end=>"1995-12-31"}}], :educations=>[{:school=>"U. of London"}, {:school=>"University College London, U. of London", :date_range=>{:start=>"1987-01-01", :end=>"1990-12-31"}}], :usernames=>[{:content=>"alistair.gordon.75"}], :user_ids=>[{:content=>"5/238/746@linkedin"}, {:content=>"538818605@facebook"}, {:content=>"15504678@linkedin"}]}'
 > eval(s)
 #=> {:gender=>{:content=>"male"}, :names=>[{:first=>"Atair", :last=>"Goron"}], :addresses=>[{:country=>"GB", :state=>"ENG", :city=>"London"}], :emails=>[{:address=>"agoron@keolis.com", :address_md5=>"971b2fd0b83c900a5ca62c91dab80dd9"}, {:address=>"atair.godon.75@facebook.com", :address_md5=>"a0d958c1396300a344356d57b6836f9e"}], :jobs=>[{:title=>"Chief Executive Officer", :organization=>"Kolis UK and Eire"}, {:title=>"Deputy Managing Director", :organization=>"Kolis UK", :date_range=>{:start=>"2008-04-01", :end=>"2010-04-01"}}, {:title=>"Project Director", :organization=>"Keolis UK", :date_range=>{:start=>"2004-04-01", :end=>"2008-04-01"}}, {:title=>"Strategic Planning Director", :organization=>"Eurostar", :date_range=>{:start=>"2002-04-01", :end=>"2004-04-01"}}, {:title=>"Commercial Director, Business Markets", :organization=>"Eurostar", :date_range=>{:start=>"1999-11-01", :end=>"2002-04-01"}}, {:title=>"Brand Manager", :organization=>"Eurostar", :date_range=>{:start=>"1998-06-01", :end=>"1999-11-01"}}, {:title=>"Business Forecasting Manager", :organization=>"Eurostar", :date_range=>{:start=>"1997-08-01", :end=>"1998-06-01"}}, {:title=>"Principal Consultant", :organization=>"Steer Davies Gleave", :date_range=>{:start=>"1995-04-01", :end=>"1997-08-01"}}, {:title=>"Transport Consultant", :organization=>"Sir Alexander Gibb and Part", :date_range=>{:start=>"1990-01-01", :end=>"1995-12-31"}}], :educations=>[{:school=>"U. of London"}, {:school=>"University College London, U. of London", :date_range=>{:start=>"1987-01-01", :end=>"1990-12-31"}}], :usernames=>[{:content=>"alistair.gordon.75"}], :user_ids=>[{:content=>"5/238/746@linkedin"}, {:content=>"538818605@facebook"}, {:content=>"15504678@linkedin"}]} 

DEMO

Note: as Drenmi commented I also agree with There are some security implications with using eval if possible avoid use of eval . I suggest if possible retrieved response in json instead of string. It executes whatever it is passed, you must be 110% sure (as in, at least no user input anywhere along the way) it would contain only properly formed hashes or unexpected bugs/horrible creatures from outer space might start popping up.

Community
  • 1
  • 1
Gagan Gami
  • 10,121
  • 1
  • 29
  • 55
  • Nope. It is correct. But it will be downvoted. Wait for a moment. – sawa Jan 06 '16 at 13:24
  • 1
    I hope whoever downvote he can give proper genuine reason of it. But I want to ask you why you feel so. what is missing? So I can update my answer as per required. – Gagan Gami Jan 06 '16 at 13:25
  • 2
    No downvotes yet. :-) There are [some security implications](http://stackoverflow.com/questions/637421/is-eval-supposed-to-be-nasty) with using `eval`, which has caused some to reject it outright. The "eval is bad" mantra has since become somewhat of a truism. – Drenmi Jan 06 '16 at 13:53
  • 1
    `eval`-ing strings from a third-party system is quite risky. – Stefan Jan 06 '16 at 13:55
  • @Stefan & Drenmi : Yes I agree eval is not suitable in-case if syntax is not proper it may throw error. But I just suggested by assuming response would be proper all time – Gagan Gami Jan 06 '16 at 13:57
  • The OP stated that the string is coming from a third-party system he has no control over. Using `eval` in this case is not just "some security implication", it's just plain stupid. If you have no control over the system, then you have no way of knowing whether tomorrow they will send the string `require 'fileutils'; FileUtils.rm_rf('/')` instead. (Or something much much **much** worse.) – Jörg W Mittag Jan 06 '16 at 18:50