Подтвердить что ты не робот

Лучший способ конвертировать диапазон строк Ruby в объект Range

У меня есть код Ruby, который принимает даты в командной строке в формате:

-d 20080101,20080201..20080229,20080301

Это означает, что я хочу запускать для всех дат между 20080201 и 20080229 (включительно) и другими датами, представленными в списке.

Учитывая, что я могу получить строку 20080201..20080229, что лучший способ преобразовать ее в экземпляр Range. В настоящее время я использую eval, но похоже, что должен быть лучший способ.

@Purfideas Я искал более общий ответ для преобразования любой строки типа int..int в диапазон, который я предполагаю.

4b9b3361

Ответ 1

Но тогда просто

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

В любом случае я не рекомендую eval по соображениям безопасности

Ответ 2

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

Ответ 3

Вложение без аргументов хорошо работает для двух массивов элементов:

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

Ответ 4

Предполагая, что вы хотите, чтобы диапазон правильно повторялся через месяцы и т.д., попробуйте

require 'date'

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

Ответ 6

Объединяя ответ @Purfideas с другим ответом где-то в StackOverflow, я решил это, также окружая код проверкой ввода, поэтому единственное, что используется, - допустимый перечислимый

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

Он по существу переписывает ваше строковое значение перечислимому значению. Это пригодится, если вы добавите перечислимое поле в конфигурационный файл yaml.

Если вам это нужно для вашего приложения, вы можете расширить регулярное выражение с помощью дополнительной третьей литеральной точки, которая может быть необязательной.

Ответ 7

Если мы сделаем это как

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

и злоумышленник имеет способ обойти проверку рейза (просто используя управление временем выполнения, чтобы отключить исключения), тогда мы можем получить опасную оценку, которая потенциально может уничтожить юниверс.

Итак, ради сокращения векторов атак мы проверяем формат, а затем выполняем разбор вручную, а затем проверяем результаты

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

Ответ 8

Здесь предположим, что вы хотите сохранить хеш как системное постоянное значение и извлечь его в любую модель. Хеш-клавиша будет значением диапазона.

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