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

时间:2008-09-10 05:28:46

标签: ruby

我有一些Ruby代码,它以格式在命令行上显示日期:

-d 20080101,20080201..20080229,20080301

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

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

@Purfideas我正在寻找一个更通用的答案来将int..int类型的任何字符串转换为我猜的范围。

9 个答案:

答案 0 :(得分:33)

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

答案 1 :(得分:14)

然后就这样做

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

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

答案 2 :(得分:7)

没有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

答案 3 :(得分:2)

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

require 'date'

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

答案 4 :(得分:1)

这个here有一个宝石。使用正则表达式来验证字符串(没有SQL注入恐惧),然后使用eval。

答案 5 :(得分:0)

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

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

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

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

答案 6 :(得分:0)

如果我们这样做

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

并且攻击者有一种绕过加注检查的方法(只需通过操纵运行时来禁用异常)然后我们就可以得到一个危险的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

答案 7 :(得分:0)

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

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

答案 8 :(得分:0)

我有类似的要求,尽管在我的情况下,字符串有两种可能的格式,有时它们是单个数字字符串,例如“7”,其他时候它们是范围,例如“10-14”。无论哪种方式,我都想将字符串转换为可枚举的数字集合。

我的方法(受 highest voted answer 启发)是:

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

如果您认为这样更易读,也可以将其作为(长)单行完成:

from_string.include?('-') ? : Range.new(*from_string.split('-').map(&:to_i)) : [from_string.to_i]

我正在处理一长串已知字符串,而不是处理任意用户输入,因此这不能防止恶意输入。