Necesito una función is_an_integer
, donde
"12".is_an_integer?
devuelve verdadero"blah".is_an_integer?
devuelve falso
¿Cómo puedo hacer esto en Ruby? Escribiría una expresión regular pero supongo que hay un ayudante para esto que no conozco.
Necesito una función is_an_integer
, donde
"12".is_an_integer?
devuelve verdadero"blah".is_an_integer?
devuelve falso¿Cómo puedo hacer esto en Ruby? Escribiría una expresión regular pero supongo que hay un ayudante para esto que no conozco.
Respuestas:
Puedes usar expresiones regulares. Aquí está la función con las sugerencias de @ janm.
class String
def is_i?
!!(self =~ /\A[-+]?[0-9]+\z/)
end
end
Una versión editada según el comentario de @wich:
class String
def is_i?
/\A[-+]?\d+\z/ === self
end
end
En caso de que solo necesite verificar números positivos
if !/\A\d+\z/.match(string_to_check)
#Is not a positive number
else
#Is all good ..continue
end
/regexp/ === self
lugar de la !!(self =~ /regexp/)
construcción. Puede usar la clase de caracteres '\ d' en lugar de[0-9]
Bueno, aquí está la manera fácil:
class String
def is_integer?
self.to_i.to_s == self
end
end
>> "12".is_integer?
=> true
>> "blah".is_integer?
=> false
No estoy de acuerdo con las soluciones que provocan una excepción para convertir la cadena: las excepciones no son el flujo de control, y es mejor que lo haga de la manera correcta. Dicho esto, mi solución anterior no trata con enteros que no son de base 10. Así que aquí está la manera de hacerlo sin recurrir a excepciones:
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
?
Puede usar Integer(str)
y ver si aumenta:
def is_num?(str)
!!Integer(str)
rescue ArgumentError, TypeError
false
end
Cabe señalar que, si bien esto devuelve verdadero para "01"
, no lo es para "09"
, simplemente porque 09
no sería un literal entero válido. Si ese no es el comportamiento que desea, puede agregarlo 10
como un segundo argumento para Integer
que el número siempre se interprete como base 10.
#to_i
están demasiado rotos debido a su permisividad.
Integer()
es canónico porque con Integer ()
usted sabe con certeza que cualquier cosa que Ruby considere un literal entero será aceptada, y todo lo demás será rechazado. Duplicar lo que el lenguaje ya le brinda es posiblemente un olor a código peor que usar excepciones para el control.
Puedes hacer un trazador de líneas:
str = ...
int = Integer(str) rescue nil
if int
int.times {|i| p i}
end
o incluso
int = Integer(str) rescue false
Dependiendo de lo que intente hacer, también puede usar directamente un bloque de inicio y final con cláusula de rescate:
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
y false
sino MatchData
casos ynil
!!
o úselo present?
si necesita un booleano !!( "12".match /^(\d)+$/ )
o "12".match(/^(\d)+$/).present?
(este último requiere Rails / soporte activo)
Ruby 2.6.0 habilita la conversión a un número entero sin generar una excepción , y regresará nil
si falla la conversión . Y dado que en nil
su mayoría se comporta como false
en Ruby, puede verificar fácilmente un número entero como este:
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_
. Me parece tonto en los métodos de interrogación, me gusta "04".integer?
mucho más que "foo".is_integer?
."01"
y tal.integer?("a string")
ftl.
String#integer?
es el tipo de parche común que a cada codificador de Ruby y su primo le gusta agregar al lenguaje, lo que lleva a bases de código con tres implementaciones sutilmente incompatibles y una rotura inesperada. Aprendí esto de la manera difícil en grandes proyectos de Ruby.
La mejor y más simple forma es usar 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
también es bueno pero volverá 0
porInteger nil
Yo prefiero:
config / initializers / string.rb
class String
def number?
Integer(self).is_a?(Integer)
rescue ArgumentError, TypeError
false
end
end
y entonces:
[218] pry(main)> "123123123".number?
=> true
[220] pry(main)> "123 123 123".gsub(/ /, '').number?
=> true
[222] pry(main)> "123 123 123".number?
=> false
o verifica el número de teléfono:
"+34 123 456 789 2".gsub(/ /, '').number?
Una forma mucho más simple podría ser
/(\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, me gusta el enfoque de excepción, aunque lo haría un poco más conciso:
class String
def integer?(str)
!!Integer(str) rescue false
end
end
Sin embargo, como ya han dicho otros, esto no funciona con cadenas Octal.
Ruby 2.4 tiene Regexp#match?
: (con a ?
)
def integer?(str)
/\A[+-]?\d+\z/.match? str
end
Para versiones anteriores de Ruby, hay Regexp#===
. Y aunque generalmente se debe evitar el uso directo del operador de igualdad de casos, aquí se ve muy limpio:
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
Esto podría no ser adecuado para todos los casos simplemente usando:
"12".to_i => 12
"blah".to_i => 0
también podría hacer para algunos.
Si es un número y no 0, devolverá un número. Si devuelve 0, es una cadena o 0.
"12blah".to_i => 12
. Esto podría causar algunos problemas en escenarios extraños.
Aquí está mi solución:
# /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
Y así es como funciona:
/^(\d)+$/
es una expresión regular para encontrar dígitos en cualquier cadena. Puede probar sus expresiones y resultados de expresiones regulares en http://rubular.com/ .IntegerRegex
guardamos en una constante para evitar la asignación innecesaria de memoria cada vez que lo usamos en el método.integer?
es un método interrogativo que debería devolver true
o false
.match
es un método en cadena que coincide con las ocurrencias según la expresión regex dada en el argumento y devuelve los valores coincidentes o nil
.!!
convierte el resultado del match
método en booleano equivalente.String
clase existente es parchear mono, que no cambia nada en las funcionalidades de String existentes, sino que simplemente agrega otro método nombrado integer?
en cualquier objeto String.Ampliando la respuesta de @ rado anterior, también se podría usar una declaración ternaria para forzar el retorno de booleanos verdaderos o falsos sin el uso de doble explosión. De acuerdo, la versión de doble negación lógica es más concisa, pero probablemente más difícil de leer para los recién llegados (como yo).
class String
def is_i?
self =~ /\A[-+]?[0-9]+\z/ ? true : false
end
end
Para casos más generalizados (incluidos números con punto decimal), puede probar el siguiente método:
def number?(obj)
obj = obj.to_s unless obj.is_a? String
/\A[+-]?\d+(\.[\d]+)?\z/.match(obj)
end
Puede probar este método en una sesión 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
Para obtener una explicación detallada de la expresión regular involucrada aquí, consulte este artículo del blog :)
obj.is_a? String
porque String # to_s se devolverá, lo que supongo que no requiere demasiado procesamiento en comparación con la .is_a?
llamada. De esta manera, solo realizará una llamada en esta línea en lugar de una o dos. Además, podría incluir directamente !!
dentro del number?
método, porque por convención, ?
se supone que un nombre de método que termina devuelve un valor booleano. ¡Saludos!
Me gusta lo siguiente, directo:
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
Cuidado sin embargo:
is_integer?('123sdfsdf')
=> true
No estoy seguro de si esto sucedió cuando se hizo esta pregunta, pero para cualquiera que se encuentre con esta publicación, la forma más simple es:
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?
funcionará con cualquier objeto.
"12".is_an_integer? == true
"not12".is_an_integer? == false
12.is_an_integer? == true