Change string to hash with ruby - ruby

I have ugly string that looks like this:
"\"New\"=>\"0\""
Which will be the best way to converting it into hash object?

Problem with "\"New\"=>\"0\"" is it does not look like a Hash. So first step should be to manipulate it to look like a Hash:
"{" + a + "}"
# => "{\"New\"=>\"0\"}"
Now once you have a hash looking string you can convert it into Hash like this:
eval "{" + a + "}"
# => {"New"=>"0"}
However there is still one issue, eval is not safe and inadvisable to use. So lets manipulate the string further to make it look json-like and use JSON.parse:
require `json`
JSON.parse ("{" + a + "}").gsub("=>",":")
# => {"New"=>"0"}

How about JSON.parse(string.gsub("=>", ":"))

You can use regex to pull out the key and value. Then create Hash directly
Hash[*"\"New\"=>\"0\"".scan(/".*?"/)]
Hard to nail down the best way if you can't tell us exactly the general format of those strings. You may not even need the regex. eg
Hash[*"\"New\"=>\"0\"".split('"').values_at(1,3)]
Also works for "\"Rocket\"=>\"=>\""

Related

Is there a more elegant way to pad a string in Ruby?

So I have a string called borrowed_book_bitmask and I want to pad this string with another string both on the left and right. The padding is defined in some class as a constant. So I have
borrowed_book_bitmask = Module1::Model1::BITMASK_PADDING + borrowed_book_bitmask + Module1::Model1::BITMASK_PADDING
This syntax is a bit clunky and inelegant. Is there a better, more succinct way to express the above?
Assume I can't change the variable name and constant name.
You can use the center method
a = "abc"
"abc.center(a.size + 4 * 2)
=> " abc "
borrowed_book_bitmask.gsub! /\A|\z/, Module1::Model1::BITMASK_PADDING
What do you mean by "pad"? Always adding the same strings on each side?
"#{Module1::Model1::BITMASK_PADDING}#{borrowed_book_bitmask}#{Module1::Model1::BITMASK_PADDING"}
What do you mean by "elegant"? Interpolation is vaguely more elegant than concatenation (and more performant IIRC, which I might not). If borrowed_book_bitmask is a method then you could embed this in a method, or use a decorator to encapsulate the functionality.
It seems to me that the inelegance comes from the repetition of the module parameter; I keep having to visually parse two long terms to check that they are the same.
pad = Module1::Model1::BITMASK_PADDING
borrowed_book_bitmask = pad + borrowed_book_bitmask + pad
...too obvious? Maybe that's only more elegant for me.

Ruby Regex text parsing

I am trying to parse a string that contains a bunch of values represented different ways. Here is what I have so far:
acc=acc.scan(/"([achievement|stat]).([\w]+.)*":[0-9]+/).flatten
which works for:
{"stat.crouchOneCm":2392,"stat.craftItem.minecraft.bed":1,"stat.craftItem.minecraft.wooden_pickaxe":1
I get (exactly what I expect):
s
crouchOneCm
2392
s
bed
1
s
wooden_pickaxe
1
but doesnt work for something like this, in addition to the stuff above:
"achievement.exploreAllBiomes":{"value":0,"progress":["Desert","DesertHills","Ocean","Beach","Savanna Plateau M","Savanna","Savanna Plateau","River"]},"stat.craftItem.minecraft.iron_pickaxe":1,"
My goal was something like:
a
exploreAllBiomes
["Desert","DesertHills","Ocean","Beach","Savanna Plateau M","Savanna","Savanna Plateau","River"]
s
iron_pickaxe
1
Anybody have an idea?
Sigh... the example string is not complete, but you're dealing with JSON...
require 'json'
hash = JSON['{"stat.crouchOneCm":2392,"stat.craftItem.minecraft.bed":1,"stat.craftItem.minecraft.wooden_pickaxe":1}']
hash
# => {"stat.crouchOneCm"=>2392,
# "stat.craftItem.minecraft.bed"=>1,
# "stat.craftItem.minecraft.wooden_pickaxe"=>1}

Combine Regexp and set of values (hash/array) to compare if a string matches in ruby

I have the following pattern to check:
"MODEL_NAME"-"ID"."FORMAT_TYPE"
where, for example:
MODEL_NAME = [:product, :brand]
FORMAT_TYPE = [:jpg, :png]
First I wanted to check if the regexp is something like:
/^\w+-\d+.\w+$/
and I have also to check if the part of my string is part of my arrays. I want something more flexible than:
/^(product|brand)-\d+.(jpg|png)$/
which I could manage through my arrays. What is a good solution to do it?
/^(#{MODEL_NAME.join '|'})-\d+\.(#{FORMAT_TYPE.join '|'})$/
# => /^(product|brand)-\d+\.(jpg|png)$/

Change string in a date format to another format

I have a string like this (YYYYMMDD):
20120225
And I want to have a string like this (MM/DD/YYYY):
02/25/2012
What's a good way of doing this in Ruby? I have thought about converting the first string to a Date, and then change the format. Or just treating the string and getting the parts I want and build the new string.
Parsing it then formatting it is the best solution:
Date.parse("20120225").strftime("%m/%d/%Y") #=> "02/25/2012"
strptime parses the string representation of date with the specified template and creates a date object.
Date.strptime('20120225', '%Y%m%d').strftime("%m/%d/%Y") #=> "02/25/2012"
Just for fun how about:
'20120225'.unpack('A4A2A2').rotate.join('/')
It's possible with regular expressions:
s1 = '20120225'
s2 = "$2/$3/$1" if s1 =~ /(\d{4})(\d{2})(\d{2})/
Or if you're sure of the format of your string and have performance issues, I think the best solution is
s2 = s1[4..5] + '/' + s1[6..7] + '/' + s1[0..3]
But if you have no performance needs, I think the solution of Andrew Marshall is better because it checks the date validity.

How do I parse a quoted string inside another string?

I want to extract the quoted substrings from inside a string. This is an example:
string = 'aaaa' + string_var_x + 'bbbb' + string_var_y
The output after parsing should be:
["'aaaa'", "'bbbb'"]
The initial solution was to string.scan /'\w'/ which is almost ok.
Still I can't get it working on more complex string, as it's implied that inside '...' there can be any kind of characters (including numbers, and !##$%^&*() whatever).
Any ideas?
I wonder if there's some way to make /'.*'/ working, but make it less greedy?
Lazy should fix this:
/'.*?'/
Another possibility is to use this:
/'[^']*'/
An alternate way to do it is:
>> %{string = 'aaaa' + string_var_x + 'bbbb' + string_var_y}.scan(/'[^'].+?'/)
#=> ["'aaaa'", "'bbbb'"]
String.scan gets overlooked a lot.

Resources