将Ruby字符串范围转换为Range对象的最佳方法

我有一些Ruby代码,它在命令行上采用以下格式的日期:

-d 20080101,20080201..20080229,20080301

这意味着我想运行20080201和20080229(含)之间的所有日期以及列表中的其他日期。

鉴于我可以获得字符串20080201..20080229将此转换为Range实例的最佳方法是什么。 目前我正在使用eval,但感觉应该有更好的方法。

@Purfideas我有点想找到一个更通用的答案,将int..int类型的任何字符串转换为Range我猜。

但那就是做

ends = '20080201..20080229'.split('..').map{|d| Integer(d)} ends[0]..ends[1] 

无论如何,出于安全考虑,我不建议使用eval

 Range.new(*self.split("..").map(&:to_i)) 

没有args的注入适用于两个元素数组:

 rng='20080201..20080229'.split('..').inject { |s,e| s.to_i..e.to_i } 

当然,这可以是通用的

 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 

假设您希望范围在几个月内正确迭代等,请尝试

 require 'date' ends = '20080201..20080229'.split('..').map{|d| Date.parse(d)} (ends[0]..ends[1]).each do |d| p d.day end 

这里有一个gem。 使用正则表达式来validation字符串(没有SQL注入恐惧),然后是eval。

将@Purfideas的答案与StackOverflow上的另一个答案结合起来,我通过输入检查来解决这个问题,因此唯一使用的是有效的可枚举

 if !value[/^[0-9]+\.\.[0-9]+$/].nil? ends = value.split('..').map{|d| Integer(d)} value = ends[0]..ends[1] end 

它实质上将您的字符串值重写为可枚举的值。 如果在yaml配置文件中添加可枚举字段,这会派上用场。

如果您的应用程序需要它,可以使用可选的第三个字符点扩展正则表达式,这可以是可选的。

如果我们这样做的话

 v= "20140101..20150101" raise "Error: invalid format: #{v}" if /\d{8}\.\.\d{8}/ !~ v r= eval(v) 

并且攻击者有一种绕过加注检查的方法(只需通过操纵运行时来禁用exception)然后我们就可以得到一个危险的eval,它可能会破坏宇宙。

因此,为了减少攻击向量,我们检查格式,然后手动进行解析,然后检查结果

 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 

这里假设您希望将哈希存储为系统常量值并在任何模型中获取它。 散列键将是范围值。

 hash_1 = {1..5 => 'a', 6..12 => 'b', 13..67 => 'c', 68..9999999 => 'd'} 

然后创建值为hash_1.to_json的系统常量。 .to_json会将您的哈希对象转换为JSON对象。 现在在代码中创建一个新的哈希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} 

新的hash_2将是必需的hash_1