2008-09-10 7 views
17

tengo algo de código Ruby que toma las fechas a la línea de comandos en el formato:mejor manera de convertir una gama cadena de Ruby a un objeto Range

-d 20080101,20080201..20080229,20080301

Qué significa que quiero ejecutar para todas las fechas entre 20080201 y 20080229 (inclusive) y las otras fechas presentes en la lista.

Dado que puedo obtener la cadena 20080201..20080229, ¿cuál es la mejor manera de convertir esto a una instancia de Rango. Actualmente estoy usando eval, pero parece que debería haber una mejor manera.

@Purfideas Estaba buscando una respuesta más general para convertir cualquier cadena de tipo int..int en un Rango, supongo.

Respuesta

14

Pero a continuación, sólo lo hacen

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

todos modos No recomiendo eval, por razones de seguridad

+0

¿Cuál es la razón de seguridad involucrados con el uso de eval? –

+1

La entrada de línea cmd es "entrada de usuario", así que ¿puede ser que esto siempre sea ejecutado por personas de confianza? esta es la inyección SQL original ... pregunte eso q en seguridad ... será su puntaje más alto. :) – Purfideas

2

suponiendo que desea que el rango para iterar a través adecuadamente meses etc, intente

require 'date' 

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

Inyectar sin args funciona bien para dos matrices de elementos:

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

Por supuesto, esto se puede hacer genérica

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 
+0

¿No debería ser eso inyectar {| s, e | (s.to_i .. e.to_i)}? Como está escrito, devuelve una matriz con un rango como un elemento único en lugar de un rango. – cpm

+0

Comentando bien después del hecho, ya que me apresuré a aceptar la respuesta, que cuando lo miré, la intención tenía sentido, pero admito que cuando lo probé encontré el mismo problema. –

+0

Se arregló la sintaxis para que ahora indique correctamente 'a.inject {| s, e | s..e} 'sin los corchetes de Array –

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

Combinando @Purfideas responden con otra respuesta alguna parte en StackOverflow, he resuelto esto también rodea el código con un control de entrada, por lo que la única cosa que solía es un enumerable válido

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

Básicamente reescribe el valor de su cadena a un valor enumerable. Esto es útil si agrega un campo enumerable en un archivo de configuración yaml.

Si lo necesita para su aplicación, puede ampliar la expresión regular con un tercer punto literal opcional, que podría ser opcional.

0

Si lo hacemos así

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

y el atacante tiene una manera de pasar por la verificación de subida (simplemente por medio de la manipulación del tiempo de ejecución para desactivar excepciones), entonces podemos obtener una eval peligroso que potencialmente destruir el universo.

Así que por el bien de la reducción de los tipos de ataque, comprobamos el formato, y luego hacer el análisis manualmente, a continuación, comprobar los resultados

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 
1

No es una joya para este here. Utiliza expresiones regulares para validar cadenas (sin miedo a la inyección de SQL) y luego evalúa.

0

Supongamos que desea almacenar el hash como un valor constante del sistema y buscarlo en cualquier modelo. La tecla hash será un valor de rango.

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

A continuación, cree la constante del sistema con el valor como hash_1.to_json. .to_json convertirá su objeto hash al objeto JSON. Ahora dentro del código crea un nuevo hash_2 hachís,

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} 

El nuevo hash_2 será el hash_1 requerido

Cuestiones relacionadas