Ho bisogno di una funzione is_an_integer
, dove
"12".is_an_integer?
ritorna vero."blah".is_an_integer?
restituisce false.
Come posso farlo in Ruby? Scriverei una regex ma suppongo che ci sia un aiuto per questo di cui non sono a conoscenza.
Ho bisogno di una funzione is_an_integer
, dove
"12".is_an_integer?
ritorna vero."blah".is_an_integer?
restituisce false.Come posso farlo in Ruby? Scriverei una regex ma suppongo che ci sia un aiuto per questo di cui non sono a conoscenza.
Risposte:
Puoi usare espressioni regolari. Ecco la funzione con i suggerimenti di @ janm.
class String
def is_i?
!!(self =~ /\A[-+]?[0-9]+\z/)
end
end
Una versione modificata secondo il commento di @wich:
class String
def is_i?
/\A[-+]?\d+\z/ === self
end
end
Nel caso in cui devi solo controllare i numeri positivi
if !/\A\d+\z/.match(string_to_check)
#Is not a positive number
else
#Is all good ..continue
end
/regexp/ === self
posto del !!(self =~ /regexp/)
costrutto. Puoi usare la classe di caratteri '\ d' invece di[0-9]
Bene, ecco il modo semplice:
class String
def is_integer?
self.to_i.to_s == self
end
end
>> "12".is_integer?
=> true
>> "blah".is_integer?
=> false
Non sono d'accordo con le soluzioni che provocano un'eccezione per convertire la stringa: le eccezioni non sono il flusso di controllo e potresti anche farlo nel modo giusto. Detto questo, la mia soluzione sopra non si occupa di numeri interi non base-10. Quindi, ecco il modo di fare senza ricorrere alle eccezioni:
class String
def integer?
[ # In descending order of likeliness:
/^[-+]?[1-9]([0-9]*)?$/, # decimal
/^0[0-7]+$/, # octal
/^0x[0-9A-Fa-f]+$/, # hexadecimal
/^0b[01]+$/ # binary
].each do |match_pattern|
return true if self =~ match_pattern
end
return false
end
end
self.to_i.to_s == self
con Integer self rescue false
?
Puoi usare Integer(str)
e vedere se genera:
def is_num?(str)
!!Integer(str)
rescue ArgumentError, TypeError
false
end
Va sottolineato che mentre ciò ritorna vero per "01"
, non per "09"
, semplicemente perché 09
non sarebbe un intero valido letterale. Se questo non è il comportamento che desideri, puoi aggiungere 10
come secondo argomento Integer
, quindi il numero viene sempre interpretato come base 10.
#to_i
sono semplicemente troppo rotti a causa della sua permissività.
Integer()
è canonico perché con Integer ()
te sai con certezza che tutto ciò che Ruby considera letterale intero verrà accettato e tutto il resto verrà rifiutato. Duplicare ciò che la lingua ti dà già è probabilmente un odore di codice peggiore rispetto all'utilizzo delle eccezioni per il controllo.
Puoi fare una fodera:
str = ...
int = Integer(str) rescue nil
if int
int.times {|i| p i}
end
o anche
int = Integer(str) rescue false
A seconda di ciò che stai cercando di fare, puoi anche utilizzare direttamente un blocco di inizio e fine con la clausola di salvataggio:
begin
str = ...
i = Integer(str)
i.times do |j|
puts j
end
rescue ArgumentError
puts "Not an int, doing something else"
end
"12".match(/^(\d)+$/) # true
"1.2".match(/^(\d)+$/) # false
"dfs2".match(/^(\d)+$/) # false
"13422".match(/^(\d)+$/) # true
true
e false
, ma MatchData
le istanze enil
!!
o l'uso present?
se avete bisogno di un valore booleano !!( "12".match /^(\d)+$/ )
o "12".match(/^(\d)+$/).present?
(questi ultimi richiedono Rails / ActiveSupport)
Ruby 2.6.0 consente il cast su un numero intero senza sollevare un'eccezione e restituirà nil
se il cast fallisce. E dal momento che nil
si comporta principalmente come false
in Ruby, puoi facilmente verificare un intero in questo modo:
if Integer(my_var, exception: false)
# do something if my_var can be cast to an integer
end
class String
def integer?
Integer(self)
return true
rescue ArgumentError
return false
end
end
is_
. Lo trovo stupido sui metodi del punto interrogativo, mi piace "04".integer?
molto meglio di "foo".is_integer?
."01"
e così.integer?("a string")
FTL.
String#integer?
è il tipo di patch comune che ad ogni programmatore di Ruby e ai loro cugini piace aggiungere al linguaggio, portando a basi di codice con tre diverse implementazioni sottilmente incompatibili e rotture inaspettate. L'ho imparato a mie spese su grandi progetti Ruby.
Il modo migliore e semplice sta usando Float
val = Float "234" rescue nil
Float "234" rescue nil #=> 234.0
Float "abc" rescue nil #=> nil
Float "234abc" rescue nil #=> nil
Float nil rescue nil #=> nil
Float "" rescue nil #=> nil
Integer
è anche buono ma tornerà 0
perInteger nil
Preferisco:
config / inizializzatori / string.rb
class String
def number?
Integer(self).is_a?(Integer)
rescue ArgumentError, TypeError
false
end
end
e poi:
[218] pry(main)> "123123123".number?
=> true
[220] pry(main)> "123 123 123".gsub(/ /, '').number?
=> true
[222] pry(main)> "123 123 123".number?
=> false
o controlla il numero di telefono:
"+34 123 456 789 2".gsub(/ /, '').number?
Un modo molto più semplice potrebbe essere
/(\D+)/.match('1221').nil? #=> true
/(\D+)/.match('1a221').nil? #=> false
/(\D+)/.match('01221').nil? #=> true
def isint(str)
return !!(str =~ /^[-+]?[1-9]([0-9]*)?$/)
end
Personalmente mi piace l'approccio basato sull'eccezione, anche se lo renderei un po 'più conciso:
class String
def integer?(str)
!!Integer(str) rescue false
end
end
Tuttavia, come altri hanno già affermato, questo non funziona con le stringhe ottali.
Ruby 2.4 ha Regexp#match?
: (con a ?
)
def integer?(str)
/\A[+-]?\d+\z/.match? str
end
Per le versioni precedenti di Ruby, c'è Regexp#===
. E sebbene l'uso diretto dell'operatore di uguaglianza di casi debba essere generalmente evitato, qui sembra molto pulito:
def integer?(str)
/\A[+-]?\d+\z/ === str
end
integer? "123" # true
integer? "-123" # true
integer? "+123" # true
integer? "a123" # false
integer? "123b" # false
integer? "1\n2" # false
Questo potrebbe non essere adatto a tutti i casi usando semplicemente:
"12".to_i => 12
"blah".to_i => 0
potrebbe anche fare per alcuni.
Se è un numero e non 0, verrà restituito un numero. Se restituisce 0 è una stringa o 0.
"12blah".to_i => 12
. Ciò potrebbe causare alcuni problemi in scenari strani.
Ecco la mia soluzione:
# /initializers/string.rb
class String
IntegerRegex = /^(\d)+$/
def integer?
!!self.match(IntegerRegex)
end
end
# any_model_or_controller.rb
'12345'.integer? # true
'asd34'.integer? # false
Ed ecco come funziona:
/^(\d)+$/
è un'espressione regex per trovare cifre in qualsiasi stringa. Puoi testare le tue espressioni regex e i risultati su http://rubular.com/ .IntegerRegex
per evitare allocazioni di memoria non necessarie ogni volta che lo usiamo nel metodo.integer?
è un metodo interrogativo che dovrebbe tornare true
o false
.match
è un metodo su stringa che corrisponde alle occorrenze secondo l'espressione regex specificata nell'argomento e restituisce i valori corrispondenti o nil
.!!
converte il risultato del match
metodo in booleano equivalente.String
classe esistente è il patching delle scimmie, che non cambia nulla nelle funzionalità String esistenti, ma aggiunge semplicemente un altro metodo chiamato integer?
su qualsiasi oggetto String.Espandendo la risposta di @ rado sopra si potrebbe anche usare un'istruzione ternaria per forzare il ritorno di booleani veri o falsi senza l'uso del doppio botto. Certo, la versione con doppia negazione logica è più concisa, ma probabilmente più difficile da leggere per i nuovi arrivati (come me).
class String
def is_i?
self =~ /\A[-+]?[0-9]+\z/ ? true : false
end
end
Per casi più generalizzati (inclusi numeri con punto decimale), puoi provare il seguente metodo:
def number?(obj)
obj = obj.to_s unless obj.is_a? String
/\A[+-]?\d+(\.[\d]+)?\z/.match(obj)
end
Puoi testare questo metodo in una sessione irb:
(irb)
>> number?(7)
=> #<MatchData "7" 1:nil>
>> !!number?(7)
=> true
>> number?(-Math::PI)
=> #<MatchData "-3.141592653589793" 1:".141592653589793">
>> !!number?(-Math::PI)
=> true
>> number?('hello world')
=> nil
>> !!number?('hello world')
=> false
Per una spiegazione dettagliata del regex coinvolto qui, consulta questo articolo del blog :)
obj.is_a? String
perché String # to_s restituirà se stesso, il che immagino non richieda troppe elaborazioni rispetto alla .is_a?
chiamata. In questo modo, effettuerai solo una chiamata in questa linea anziché una o due. Inoltre, è possibile includere direttamente !!
all'interno del number?
metodo, poiché, per convenzione, un nome di metodo che termina ?
dovrebbe restituire un valore booleano. Saluti!
Mi piace il seguente, semplice:
def is_integer?(str)
str.to_i != 0 || str == '0' || str == '-0'
end
is_integer?('123')
=> true
is_integer?('sdf')
=> false
is_integer?('-123')
=> true
is_integer?('0')
=> true
is_integer?('-0')
=> true
Attenzione però:
is_integer?('123sdfsdf')
=> true
Non sono sicuro se questo fosse in giro quando viene posta questa domanda, ma per chiunque si imbatta in questo post, il modo più semplice è:
var = "12"
var.is_a?(Integer) # returns false
var.is_a?(String) # returns true
var = 12
var.is_a?(Integer) # returns true
var.is_a?(String) # returns false
.is_a?
funzionerà con qualsiasi oggetto.
"12".is_an_integer? == true
"not12".is_an_integer? == false
12.is_an_integer? == true