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/ === selfposto 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 == selfcon 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é 09non sarebbe un intero valido letterale. Se questo non è il comportamento che desideri, puoi aggiungere 10come secondo argomento Integer, quindi il numero viene sempre interpretato come base 10.
#to_isono 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
truee false, ma MatchDatale 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à nilse il cast fallisce. E dal momento che nilsi comporta principalmente come falsein 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à 0perInteger 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/ .IntegerRegexper evitare allocazioni di memoria non necessarie ogni volta che lo usiamo nel metodo.integer?è un metodo interrogativo che dovrebbe tornare trueo 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 matchmetodo in booleano equivalente.Stringclasse 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? Stringperché 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