vi el debate no resuelto sobre el modelo + excepciones vs expresiones regulares y pensé que iba a tratar de referencia todo y producir una respuesta objetiva:
Aquí es la fuente para el mejor de los casos y lo peor de cada método intentado aquí:
require "benchmark"
n = 500000
def is_float?(fl)
!!Float(fl) rescue false
end
def is_float_reg(fl)
fl =~ /(^(\d+)(\.)?(\d+)?)|(^(\d+)?(\.)(\d+))/
end
class String
def to_float
Float self rescue (0.0/0.0)
end
end
Benchmark.bm(7) do |x|
x.report("Using cast best case") {
n.times do |i|
temp_fl = "#{i + 0.5}"
is_float?(temp_fl)
end
}
x.report("Using cast worst case") {
n.times do |i|
temp_fl = "asdf#{i + 0.5}"
is_float?(temp_fl)
end
}
x.report("Using cast2 best case") {
n.times do |i|
"#{i + 0.5}".to_float
end
}
x.report("Using cast2 worst case") {
n.times do |i|
"asdf#{i + 0.5}".to_float
end
}
x.report("Using regexp short") {
n.times do |i|
temp_fl = "#{i + 0.5}"
is_float_reg(temp_fl)
end
}
x.report("Using regexp long") {
n.times do |i|
temp_fl = "12340918234981234#{i + 0.5}"
is_float_reg(temp_fl)
end
}
x.report("Using regexp short fail") {
n.times do |i|
temp_fl = "asdf#{i + 0.5}"
is_float_reg(temp_fl)
end
}
x.report("Using regexp long fail") {
n.times do |i|
temp_fl = "12340918234981234#{i + 0.5}asdf"
is_float_reg(temp_fl)
end
}
end
con los siguientes resultados con mri193:
user system total real
Using cast best case 0.608000 0.000000 0.608000 ( 0.615000)
Using cast worst case 5.647000 0.094000 5.741000 ( 5.745000)
Using cast2 best case 0.593000 0.000000 0.593000 ( 0.586000)
Using cast2 worst case 5.788000 0.047000 5.835000 ( 5.839000)
Using regexp short 0.951000 0.000000 0.951000 ( 0.952000)
Using regexp long 1.217000 0.000000 1.217000 ( 1.214000)
Using regexp short fail 1.201000 0.000000 1.201000 ( 1.202000)
Using regexp long fail 1.295000 0.000000 1.295000 ( 1.284000)
Dado que se trata de sólo algoritmos de tiempo lineal creo que utilizamos mediciones empíricas para hacer generalizaciones. Es fácil ver que la expresión regular es más consistente y solo fluctuará un poco en función de la longitud de la secuencia que se transmita. El lanzamiento es claramente más rápido cuando no hay falla, y mucho más lento cuando hay fallas.
Si comparamos los tiempos de éxito, podemos ver que el mejor de los casos fundido es de aproximadamente 0,3 segundos más rápido que el mejor de los casos de expresiones regulares. Si dividimos esto por la cantidad de tiempo en el caso peor de los casos se puede estimar el número de carreras que se necesitaría para romper incluso con excepciones ralentizar el arrojado a igualar las velocidades de expresiones regulares. Alrededor de 6 segundos buceados por .3 nos da alrededor de 20. Por lo tanto, si el rendimiento es importante y espera que falle menos de 1 de cada 20 de su prueba, entonces se utilizarán cast + excepciones.
JRuby 1.7.4 tiene resultados completamente diferentes:
user system total real
Using cast best case 2.575000 0.000000 2.575000 ( 2.575000)
Using cast worst case 53.260000 0.000000 53.260000 (53.260000)
Using cast2 best case 2.375000 0.000000 2.375000 ( 2.375000)
Using cast2 worst case 53.822000 0.000000 53.822000 (53.822000)
Using regexp short 2.637000 0.000000 2.637000 ( 2.637000)
Using regexp long 3.395000 0.000000 3.395000 ( 3.396000)
Using regexp short fail 3.072000 0.000000 3.072000 ( 3.073000)
Using regexp long fail 3.375000 0.000000 3.375000 ( 3.374000)
Cast es sólo marginalmente más rápido en el mejor de los casos (el 10%). Suponiendo que esta diferencia es apropiada para hacer generalizaciones (no creo que sea así), entonces el punto de equilibrio está en algún lugar entre 200 y 250 carreras y solo 1 causa una excepción.
excepciones por lo que sólo deben usarse cuando ocurre cosas realmente excepcionales, esta es una decisión para usted y su código base. Cuando no se usan el código en el que están, puede ser más simple y más rápido.
Si el rendimiento no importa, probablemente debería simplemente siguiendo lo que las convenciones del equipo o de la base de código que ya tiene y pasar por alto todo esto esta respuesta.
¡Excelente respuesta! Nota: Esta expresión regular ha evolucionado un poco en la implementación de Rubinius, consulte las especificaciones en https://github.com/rubinius/rubinius/blob/master/spec/ruby/core/string/to_f_spec.rb para obtener más información. Tenga en cuenta también que si está utilizando esto para validar la entrada del usuario, es posible que desee omitir el soporte para guiones bajos y simplemente usar la expresión regular de Rubinius como inspiración :) – captainpete
Corrección, Rubinius todavía usa la misma expresión regular para Float(). Encuentre el código en https://github.com/rubinius/rubinius/blob/master/kernel/common/kernel19.rb – captainpete