[ACCEPTED]-What is the best way to convert a Ruby string range to a Range object-ruby
Range.new(*self.split("..").map(&:to_i))
0
But then just do
ends = '20080201..20080229'.split('..').map{|d| Integer(d)}
ends[0]..ends[1]
anyway I don't recommend 1 eval, for security reasons
Inject with no args works well for two element 1 arrays:
rng='20080201..20080229'.split('..').inject { |s,e| s.to_i..e.to_i }
Of course, this can be made generic
class Range
def self.from_ary(a)
a.inject{|s,e| s..e }
end
end
rng = Range.from_ary('20080201..20080229'.split('..').map{|s| s.to_i})
rng.class # => Range
assuming you want the range to iterate properly 1 through months etc, try
require 'date'
ends = '20080201..20080229'.split('..').map{|d| Date.parse(d)}
(ends[0]..ends[1]).each do |d|
p d.day
end
Combining @Purfideas answer with another 10 answer somewhere on StackOverflow, I solved 9 this by also surrounding the code with an 8 input check, so the only thing used is a 7 valid enumerable
if !value[/^[0-9]+\.\.[0-9]+$/].nil?
ends = value.split('..').map{|d| Integer(d)}
value = ends[0]..ends[1]
end
It essentially rewrites 6 your string value to a enumerable value. This 5 comes in handy if you add a enumerable field 4 in a yaml config file.
If you need it for 3 your application, you could extend the regex 2 with an optional third literal dot, that 1 could be optional.
If we do it like
v= "20140101..20150101"
raise "Error: invalid format: #{v}" if /\d{8}\.\.\d{8}/ !~ v
r= eval(v)
and the attacker has a way 7 of bypassing the raise check (simply by 6 means of manipulating the runtime to disable 5 exceptions) then we can get a dangerous 4 eval which will potentially destroy the 3 universe.
So for the sake of reducing attack 2 vectors, we check the format, and then do 1 the parsing manually, then check the results
v= "20140101..20150101"
raise "Error: invalid format: #{v}" if /\d{8}\.\.\d{8}/ !~ v
r= Range.new(*v.split(/\.\./).map(&:to_i))
raise "Error: invalid range: #{v}" if r.first> r.last
Here suppose you want to store the hash 7 as a system constant value and fetch it 6 in any model. The hash key will be a range 5 value.
hash_1 = {1..5 => 'a', 6..12 => 'b', 13..67 => 'c', 68..9999999 => 'd'}
Then create the system constant with 4 value as hash_1.to_json. .to_json will convert 3 your hash object to JSON object. Now inside 2 the code create a new hash hash_2,
JSON.parse(SystemConstant.get('Constant_name')).each{|key,val| temp_k=key.split('..').map{|d| Integer(d)}; hash_2[temp_k[0]..temp_k[1]] = val}
The new 1 hash_2 will be the required hash_1
I had a similar requirement although in 12 my case the strings were in two possible 11 formats, occasionally they were single number 10 strings such as "7", other times 9 they were ranges such as "10-14". Either 8 way I wanted to turn the string into an 7 Enumerable collection of numbers.
My approach 6 (inspired by the highest voted answer) was:
def numbers(from_string:)
if from_string.include?('-')
return Range.new(*from_string.split('-').map(&:to_i))
else
return [from_string.to_i] # put number in an array so we can enumerate over it
end
end
It can also be done 5 as a (long) one-liner if you think that's 4 more readable:
from_string.include?('-') ? Range.new(*from_string.split('-').map(&:to_i)) : [from_string.to_i]
I was processing a long list 3 of known strings, not dealing with arbitrary 2 user input so this doesn't guard against 1 malicious input.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.