Sorry for the bad question title. My brain is broken!!
Problem:
I have a string of integers that can be separated by a comma, hyphen or both. e.g.
str = '3,7-17,21'
I need to take those numbers and reduce them by 1 without losing their position in that string.
When I split, I lose commas and hyphens so their positions change.
Is there a nice way to turn my string into 2,6-16,20?
I started on the following but just ended up in a rabbit hole:
def reduce_hours(hours)
hours
.enum_for(:scan, /\d+/)
.map { Regexp.last_match(0) }
.map(&:to_i)
.map { |hour| hour - 1 }
.then { hours }
end
hours = '3,7-17,21'
It just returns the original string. When I debug, it does match the numbers individually and reduce them by 1. It just doesn’t return those changes to the original string. Am I close with that snippet?
Thank you in advance.
>Solution :
enum_for(:scan, ...), Regexp.last_match(0), then – you’re overthinking it.
You can just use gsub to replace each numeric substring by its predecessor:
str = '3,7-17,21'
str.gsub(/\d+/) { |hour| hour.to_i - 1 }
#=> "2,6-16,20"
The to_i round trip is needed, because strings can’t be decremented directly.
The opposite direction is even easier: (via String#succ)
"2,6-16,20".gsub(/\d+/, &:succ)
#=> "3,7-17,21"