views:

103

answers:

5

Hi,

I would like to turn a string with opening hours like this:

"Monday-Friday>10:00-18:00;Saturday>12:00-17:00;Sunday>12:00-15:00"

Into this:

[ {:period => "Monday-Friday", :hours => "10:00-18:00"}, {:period => "Saturday", :hours => "12:00-17:00"}, {:period => "Sunday", :hours => "12:00-15:00"} ]

I'm trying it with the String.scan() method but can't figure out the Regexp.

Also if you have any suggestions of how to do it in reverse the best way (i.e. when getting the opening hours from a form.)

Update - Thank you all found perfect solutions! Right now I'm using (thanks kejadlen):

str.scan(/([\w-]+)>([\d:-]+)-([\d:]+)/).map { |(p,o,c)| {:period => p, :opens => o, :closes => c} }

But now how about reversing it =) So given:

[ {:opens=>"10:00", :closes=>"18:00", :period=>"Monday-Friday"}, 
  {:opens=>"12:00", :closes=>"17:00", :period=>"Saturday"}, 
  {:opens=>"12:00", :closes=>"15:00", :period=>"Sunday"} ]

I want to merge it to:

"Monday-Friday>10:00-18:00;Saturday>12:00-17:00;Sunday>12:00-15:00"
A: 

Try this:

String S =  ([^\>]*)\>([^\;]*)\;
String T = " {:period => $1, :hours => $2}, "
originalString.replaceAll(S,T);

Might have to play with the regexp a little more but that should about do it.

Edit - Well, you asked for the answer in the context of ruby and I gave you the Java answer but the regular expression should work anyway...

Ben
um, except that I'm guessing the OQ wanted an array of hashes as output, not a string serialisation that needs eval'ing.
p00ya
@P00ya - Your'e right... Wasn't clear though.
Ben
+2  A: 

this is how I would do it

str="Monday-Friday>10:00-18:00;Saturday>12:00-17:00;Sunday>12:00-15:00"
periods = str.split(';') 
#=> ["Monday-Friday>10:00-18:00", "Saturday>12:00-17:00", "Sunday>12:00-15:00"]
period_array=[]
periods.each do |period| 
  period_with_hours = period.split('>')
  period_array << {:period =>  period_with_hours.first, :hours => period_with_hours.last}
end

period_array

#=> [{:period=>"Monday-Friday", :hours=>"10:00-18:00"}, {:period=>"Saturday", :hours=>"12:00-17:00"}, {:period=>"Sunday", :hours=>"12:00-15:00"}]
nas
Just for fun... `periods = str.split(';').inject([]) {|n,i| n << Hash[*[:period, :hours].zip(i.split('>')).flatten] })`
kejadlen
Or... `str.scan(/([\w-]+)>([\d:-]+)/).map {|(p,h)| {:period => p, :hours => h }}`
kejadlen
Yes, that definitely valid for fun :). Ruby allows us to put a long chain of methods on a single line but I think its not prudent to put everything on a line if the intention of your code gets a bit muddled. I try to put things in temporary variables before calling another method on it if that makes the intention of the code a bit more clear. For instance, if you look at my code, it clearly says what it is doing the moment you look at it, first split string by ';' and create an array and then split on '>' to create each element of the array and create hash.Just following clean code principles
nas
You don't have to write it in a single line. Functional-style solutions (using `map`, `inject` etc.) are considered more elegant and thus preferred among Rubyists.
Mladen Jablanović
@Mladen I do agree with that as long as the code intention is clear
nas
+3  A: 

If you prefer one-liners:

s = "Monday-Friday>10:00-18:00;Saturday>12:00-17:00;Sunday>12:00-15:00"
s.split(/;/).map{|i| Hash[[[:period, :hours], i.split(/>/)].transpose]}
# or
s.split(/;/).map{|i| p, h = i.split(/>/); {:period => p, :hours => h}}
#=> [{:period=>"Monday-Friday", :hours=>"10:00-18:00"}, {:period=>"Saturday", :hours=>"12:00-17:00"}, {:period=>"Sunday", :hours=>"12:00-15:00"}]

Edit:

Regarding the reverse, this should do the job:

a.map{|i| "#{i[:period]}>#{i[:opens]}-#{i[:closes]}"}.join(';')
=> "Monday-Friday>10:00-18:00;Saturday>12:00-17:00;Sunday>12:00-15:00"
Mladen Jablanović
A: 

This looks like it works

the_input.split(';').collect{|pair|
    period, hours = pair.split('>')
    {:period => period, :hours => hours}
}
=> [{:hours=>"10:00-18:00", :period=>"Monday-Friday"}, {:hours=>"12:00-17:00", :
period=>"Saturday"}, {:hours=>"12:00-15:00", :period=>"Sunday"}]
Gishu
A: 
str.scan(/([\w-]+)>([\d:-]+)/).map {|(p,h)| {:period => p, :hours => h }}
kejadlen