2009-08-17 4 views
10

Quería validar la 'numericalidad' de una cadena (no es un atributo en un modelo de registro activo). Solo necesito que sea una base válida 10, cadena entera positiva. Estoy haciendo esto:Implementación de Ruby is_numeric? para cadenas, necesita mejores alternativas

class String 
    def numeric? 
    # Check if every character is a digit 
    !!self.match(/\A[0-9]+\Z/) 
    end 
end 

class String 
    def numeric? 
    # Check is there is *any* non-numeric character 
    !self.match(/[^0-9]/) 
    end 
end 

¿Cuál de estas opciones es más plausible? O, ¿hay alguna otra mejor implementación?

+0

Por curiosidad, ¿por qué el multiplicador '{1,1}'? Por defecto, todas las clases de caracteres y literales se emparejan exactamente una vez, a menos que se especifique lo contrario. Esto es redundante. –

+0

¡Pobre de mí! Lo eliminaré de una vez. – Swanand

+0

Pregunta relacionada: http://stackoverflow.com/questions/694176/retrieve-number-from-the-string-pattern-using-regular-expression –

Respuesta

10

Por favor asegúrese de que el uso \A y \Z en lugar de ^ y $, para que coincida con la cadena completa en lugar de sólo una sola línea en la cadena. Si desea evitar que coincida una cadena con una nueva línea final, use '\ z' al final. Para más problemas, vea The Regex Tutorial on anchors.

Por ejemplo, /^[0-9]+$/ que coincidan las siguientes:

foo 
1234 
bar 

pero /\A[0-9]+\Z/ no.

5

La primera me parece sensata.

Aunque me gustaría llamar al método numeric?. No soy un gran admirador de los métodos is_foo?. Tienen sentido en idiomas que no tienen signos de interrogación en los nombres de los métodos (is_foo, isFoo), pero con el signo de interrogación, el is parece redundante.

+0

Terminé usando el segundo. – Swanand

1

El segundo finalizará más rápido en el caso de una cadena no numérica, ya que se rechazará en el primer carácter incorrecto.

También, consulte el método de cadena # to_i - que posiblemente hace lo que quiere:
http://www.ruby-doc.org/core/classes/String.html#M000787

+0

el problema con to_i es que nunca se sabe si es 0 o no es un número. – moogs

+0

Exactamente por qué no lo usé. – Swanand

1

No sé si esto es rápido, pero me gusta:

class String 
def numeric? 
    true if Integer(object) rescue false 
end 
end 

Maneja números negativos también. Y si alguna vez desea admitir flotadores en el futuro, simplemente use Float()

+0

aw mierda, usando esto haría que "0x122" sea numérico. oh bien ... – moogs

+0

¿Esto realmente funciona? ¿De dónde viene 'object'? En mi ruby ​​1.9.2-p180 siempre devuelve 'false' porque' object' no está definido. – mark

3

No soy 100% seguro pero Rails parece estar usando /\A[+-]?\d+\Z/ para enteros.
Haga clic en la fuente espectáculo para validates_numericality_ofhere

+0

\ A -> Inicio de la cadena \ Z -> Fin de la cadena Básicamente lo mismo que estoy haciendo en la primera, excepto la parte modificadora positiva/negativa. – Swanand

0

De acuerdo a una simple referencia, el segundo método es más rápido, aunque no estoy benchmarker experto, por lo que esto podría no ser un punto de referencia válido: la lógica http://pastie.org/586777

Zalus' es correcto. Solo necesita verificar una vez para una cadena no válida.

2

Sugeriría otra forma de hacerlo. Además, como usted pidió el entero "positivo", hice dos métodos separados para el entero positivo y el entero no negativo.

class String 
    def numeric? 
    !self.match(/[^0-9]/) 
    end 

    def positive_integer? 
    self.to_i > 0 
    end 

    def nonnegative_integer? 
    self.to_i > 0 or self == '0' 
    end 
end 

Aquí está el código de referencia:

require 'benchmark' 
include Benchmark 

bmbm(100) do |x| 
    x.report('numeric?') do 
    "some invalid string".numeric? 
    end 

    x.report('positive_integer?') do 
    "some invalid string".positive_integer? 
    end 

    x.report('nonnegative_integer?') do 
    "some invalid string".nonnegative_integer? 
    end 
end 

Resultado:

numeric? 
0.000000 0.000000 0.000000 ( 0.000045) 
positive_integer? 
0.000000 0.000000 0.000000 ( 0.000012) 
nonnegative_integer? 
0.000000 0.000000 0.000000 ( 0.000015) 

Parece que positive_integer? y nonnegative_integer? son más rápidos en este micro-referencia.

Por último, como nota al margen, se puede definir integer? método de una manera similar:

class String 
    def integer? 
    self.to_i.to_s == self 
    end 
end 
0

Aviso

n = '1234' 
n.to_i.to_s == n 
=> true 

n2 = '1.3' 
n.to_i.to_s == n2 
=> false 

obras para & números enteros positivos y negativos, sino representaciones no octal/hexadecimal, flota, etc. Puede que no rinda mejor (no probado), pero no tiene sentido perder tiempo con optimizaciones prematuras.

Cuestiones relacionadas