我有一些Ruby代码,它以格式在命令行上显示日期:
-d 20080101,20080201..20080229,20080301
这意味着我想运行20080201和20080229(含)之间的所有日期以及列表中的其他日期。
鉴于我可以获得字符串20080201..20080229,将此转换为Range实例的最佳方法是什么。目前我正在使用eval,但感觉应该有更好的方法。
@Purfideas我正在寻找一个更通用的答案来将int..int类型的任何字符串转换为我猜的范围。
答案 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]
我正在处理一长串已知字符串,而不是处理任意用户输入,因此这不能防止恶意输入。