Forum: Ruby on Rails fetch the Hash from a string

249c7fd851c5c5ac5a1abdb756472ae1?d=identicon&s=25 Arup Rakshit (my-ruby)
on 2013-08-26 21:42
require 'json'

str = "1=2,3=(4=5,6=7)"
new_str = str.gsub(/=|\(|\)/) do |m|
  if m == "="
    m= "=>"
  elsif m == "("
    m = "{"
  else
    m = "}"
  end
end

new_str = new_str.prepend("{") << "}"
# => "{1=>2,3=>{4=>5,6=>7}}"

JSON.parse(new_str)
# ~>
/home/kirti/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/json/common.rb:155:in
`parse': 757: unexpected token at '{1=>2,3=>{4=>5,6=>7}}'
(JSON::ParserError)
# ~>  from
/home/kirti/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/json/common.rb:155:in
`parse'
# ~>  from -:15:in `<main>'


My question is how should I get the hash {1=>2,3=>{4=>5,6=>7}} from that
string?
Bee69cfed999cd13e3bff73d472a39ee?d=identicon&s=25 Hassan Schroeder (Guest)
on 2013-08-26 21:59
(Received via mailing list)
On Mon, Aug 26, 2013 at 12:42 PM, Love U Ruby <lists@ruby-forum.com>
wrote:
>
> My question is how should I get the hash {1=>2,3=>{4=>5,6=>7}} from that
> string?

Why don't you generate valid JSON in the first place?

`{1=>2,3=>{4=>5,6=>7}}.to_json` would show you what the string
should look like (and why your example is so broken).

--
Hassan Schroeder ------------------------ hassan.schroeder@gmail.com
http://about.me/hassanschroeder
twitter: @hassan
249c7fd851c5c5ac5a1abdb756472ae1?d=identicon&s=25 Arup Rakshit (my-ruby)
on 2013-08-26 22:12
Hassan Schroeder wrote in post #1119612:
> On Mon, Aug 26, 2013 at 12:42 PM, Love U Ruby <lists@ruby-forum.com>
> wrote:
>>
>> My question is how should I get the hash {1=>2,3=>{4=>5,6=>7}} from that
>> string?
>
> Why don't you generate valid JSON in the first place?
>
> `{1=>2,3=>{4=>5,6=>7}}.to_json` would show you what the string
> should look like (and why your example is so broken).

In my case the hash is inside the string,but I want the hash back from
the string? :( I don't know how to do this...
Bee69cfed999cd13e3bff73d472a39ee?d=identicon&s=25 Hassan Schroeder (Guest)
on 2013-08-26 22:40
(Received via mailing list)
On Mon, Aug 26, 2013 at 1:12 PM, Love U Ruby <lists@ruby-forum.com>
wrote:

> In my case the hash is inside the string,but I want the hash back from
> the string? :( I don't know how to do this...

If you must use that format --

2.0.0-p247 :017 > str
 => "1=2,3=(4=5,6=7)"
2.0.0-p247 :018 > eval
str.tr('()','{}').gsub(/=/,'=>').prepend('{').concat('}')
 => {1=>2, 3=>{4=>5, 6=>7}}
2.0.0-p247 :019 >


--
Hassan Schroeder ------------------------ hassan.schroeder@gmail.com
http://about.me/hassanschroeder
twitter: @hassan
Aa082c8b00a50928e5860dcd70bf2368?d=identicon&s=25 tamouse m. (tamouse_m)
on 2013-08-26 23:08
(Received via mailing list)
On Aug 26, 2013, at 2:42 PM, Love U Ruby <lists@ruby-forum.com> wrote:

>  end
> # ~>  from
> /home/kirti/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/json/common.rb:155:in
> `parse'
> # ~>  from -:15:in `<main>'
>
>
> My question is how should I get the hash {1=>2,3=>{4=>5,6=>7}} from that
> string?
>
> -

There is no JSON here at all.

Given this:
> new_str = new_str.prepend("{") << "}"
> # => "{1=>2,3=>{4=>5,6=>7}}"

You have a string which represents a what a Hash looks like. Why not run
it through eval and see what you get?

my_hash = eval(new_str)
249c7fd851c5c5ac5a1abdb756472ae1?d=identicon&s=25 Arup Rakshit (my-ruby)
on 2013-08-26 23:10
tamouse m. wrote in post #1119628:
> On Aug 26, 2013, at 2:42 PM, Love U Ruby <lists@ruby-forum.com> wrote:
>
>
> You have a string which represents a what a Hash looks like. Why not run
> it through eval and see what you get?
>
> my_hash = eval(new_str)

I was trying to avoid `eval`. I tried also the `yaml`. But no luck :(
9570b2f45e7de7a24d8f3bf4b2517192?d=identicon&s=25 Rob Biedenharn (Guest)
on 2013-08-27 02:43
(Received via mailing list)
On 2013-Aug-26, at 17:10 , Love U Ruby wrote:

> tamouse m. wrote in post #1119628:
>> On Aug 26, 2013, at 2:42 PM, Love U Ruby <lists@ruby-forum.com> wrote:
>>
>>
>> You have a string which represents a what a Hash looks like. Why not run
>> it through eval and see what you get?
>>
>> my_hash = eval(new_str)
>
> I was trying to avoid `eval`. I tried also the `yaml`. But no luck :(


If all your keys and values are just digits (i.e., String#to_i likes
them), then you can easily avoid eval and yaml. Just make your own
parser.  Here are some "learning tests" to get you started. If you avoid
scrolling down too far to see my "answer", then just make the tests pass
and you're done!

Of course, you can also expand the tests to cover even more exotic hash
keys and values, but if you go too far you've just reinvented YAML or
JSON with different syntax.

-Rob


require 'minitest/autorun'

class TestSomeCrappyMarkupLanguage < Minitest::Test
  def setup
    @str = "1=2,3=(4=5,6=7)"
  end

  def test_nil
    refute SomeCrappyMarkupLanguage.parse(nil)
  end

  def test_empty_string
    assert_equal({}, SomeCrappyMarkupLanguage.parse(""))
  end

  def test_simple_hash
    assert_equal({1=>2}, SomeCrappyMarkupLanguage.parse("1=2"))
  end

  def test_two_elements
    assert_equal({4=>5,6=>7}, SomeCrappyMarkupLanguage.parse("4=5,6=7"))
  end

  def test_nested
    expected = { 1 => 2, 3 => { 4 => 5, 6 => 7 } }
    assert_equal expected, SomeCrappyMarkupLanguage.parse(@str)
  end

end

# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...
# spoilers below...

class SomeCrappyMarkupLanguage
  def self.parse(str)
    return nil unless str
    result = {}
    str.scan(/(\d+)=((?:\([^\)]*\))|\d+),?/).each do |key,value|
      key = key.to_i
      value = value =~ /\A\d+\z/ ? value.to_i : parse(value)
      result[key] = value
    end
    result
  end
end
249c7fd851c5c5ac5a1abdb756472ae1?d=identicon&s=25 Arup Rakshit (my-ruby)
on 2013-08-27 09:55
Rob Biedenharn wrote in post #1119642:

@Rob - thanks for such an detailed answer.. :) I need to give some more
time on this...

> class SomeCrappyMarkupLanguage
>   def self.parse(str)
>     return nil unless str
>     result = {}
>     str.scan(/(\d+)=((?:\([^\)]*\))|\d+),?/).each do |key,value|
>       key = key.to_i
>       value = value =~ /\A\d+\z/ ? value.to_i : parse(value)
>       result[key] = value
>     end
>     result
>   end
> end
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.