2009-08-17 7 views
10

Volevo convalidare la "numericità" di una stringa (non è un attributo in un modello di record attivo). Ho solo bisogno che sia una base valida 10, stringa intera positiva. Sto facendo questo:L'implementazione di Ruby è_numerica? per le stringhe, sono necessarie alternative migliori

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 

Quale di questi è un'alternativa più plausibile? O, c'è qualche altra migliore implementazione?

+0

Per curiosità, perché il moltiplicatore '{1,1}'? Per impostazione predefinita, tutte le classi e i letterali dei caratteri vengono confrontati esattamente una volta, a meno che non sia diversamente specificato. Questo è ridondante. –

+0

Povero me! Lo rimuoverò subito. – Swanand

+0

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

risposta

10

Assicurarsi uso \A e \Z piuttosto che ^ e $, per abbinare l'intera stringa piuttosto che solo una singola linea nella stringa. Se vuoi evitare di far corrispondere una stringa con una nuova fine, usa '\ z' alla fine. Per ulteriori problemi, vedere The Regex Tutorial on anchors.

Per esempio, /^[0-9]+$/ corrisponde con successo quanto segue:

foo 
1234 
bar 

ma /\A[0-9]+\Z/ non lo fa.

5

Il primo mi sembra sano di mente.

Vorrei nominare il metodo numeric?, tuttavia. Non sono un grande fan dei metodi is_foo?. Hanno senso nelle lingue che non hanno punti interrogativi nei nomi dei metodi (is_foo, isFoo), ma con il punto interrogativo, il is si sente ridondante.

+0

Ho finito per usare il secondo. – Swanand

1

Il secondo terminerà più rapidamente nel caso di una stringa non numerica, poiché rifiuterà il primo carattere non valido.

Inoltre, controllare il metodo String # to_i - è forse fa ciò che si vuole:
http://www.ruby-doc.org/core/classes/String.html#M000787

+0

il problema con to_i non si sa mai se è 0 o meno un numero. – moogs

+0

Esattamente perché non l'ho usato. – Swanand

1

Non so se questo è veloce, ma mi piace:

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

gestisce i numeri negativi anche. E se mai volessi supportare i float in futuro, usa semplicemente Float()

+0

aw crap, usando questo renderebbe "0x122" numerico. vabbè .. – moogs

+0

Funziona davvero? Da dove viene l'oggetto? Sul mio ruby ​​1.9.2-p180 restituisce sempre 'false' perché' object' non è definito. – mark

3

Non sono sicuro al 100% ma Rails sembra utilizzare /\A[+-]?\d+\Z/ per i numeri interi.
Clicca in mostra fonte per validates_numericality_ofhere

+0

\ A -> Inizio della stringa \ Z -> Fine della stringa Fondamentalmente lo stesso che non ho inserito in Primo, tranne la parte modificatore positivo/negativo. – Swanand

0

Secondo un semplice punto di riferimento, il secondo approccio è più veloce, anche se io non sono esperto di benchmarker, quindi questo potrebbe non essere un punto di riferimento valida: la logica http://pastie.org/586777

Zalus' è giusto. Deve solo controllare una volta per una stringa non valida.

2

Suggerirei un altro modo di farlo. Inoltre, poiché hai chiesto un numero intero "positivo", ho realizzato due metodi separati per intero positivo e numero intero non 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 

Ecco il codice di riferimento:

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 

Risultato:

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) 

Sembra positive_integer? e nonnegative_integer? sono più veloci in questo micro-benchmark.

Infine, come nota a margine, è possibile definire integer? metodo in un modo simile:

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

Avviso

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

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

lavori per positivi & interi negativi, ma le rappresentazioni non ottale/esagonali, galleggianti, ecc. Potrebbe non funzionare al meglio (non testato), ma senza perdere tempo con ottimizzazioni premature.

Problemi correlati