Eu preciso de uma função is_an_integer
, onde
"12".is_an_integer?
retorna verdadeiro."blah".is_an_integer?
retorna falso.
Como posso fazer isso em Ruby? Eu escreveria uma regex, mas estou assumindo que existe um ajudante para isso que não conheço.
Eu preciso de uma função is_an_integer
, onde
"12".is_an_integer?
retorna verdadeiro."blah".is_an_integer?
retorna falso.Como posso fazer isso em Ruby? Eu escreveria uma regex, mas estou assumindo que existe um ajudante para isso que não conheço.
Respostas:
Você pode usar expressões regulares. Aqui está a função com as sugestões de @ janm.
class String
def is_i?
!!(self =~ /\A[-+]?[0-9]+\z/)
end
end
Uma versão editada de acordo com o comentário de @wich:
class String
def is_i?
/\A[-+]?\d+\z/ === self
end
end
Caso você precise apenas 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
vez da !!(self =~ /regexp/)
construção. Você pode usar a classe de caracteres '\ d' em vez de[0-9]
Bem, aqui está o caminho mais fácil:
class String
def is_integer?
self.to_i.to_s == self
end
end
>> "12".is_integer?
=> true
>> "blah".is_integer?
=> false
Não concordo com as soluções que provocam uma exceção para converter a string - as exceções não são o fluxo de controle e você pode fazê-lo da maneira certa. Dito isto, minha solução acima não lida com números inteiros que não sejam da base 10. Então, aqui está o caminho a seguir sem recorrer a exceções:
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
com Integer self rescue false
?
Você pode usar Integer(str)
e ver se isso gera:
def is_num?(str)
!!Integer(str)
rescue ArgumentError, TypeError
false
end
Deve-se ressaltar que, embora isso retorne true para "01"
, não retorna "09"
, simplesmente porque 09
não seria um literal inteiro válido. Se esse não é o comportamento que você deseja, você pode adicionar 10
como um segundo argumento para Integer
que o número seja sempre interpretado como base 10.
#to_i
são muito quebrados por causa de sua permissividade.
Integer()
é canônico, porque com Integer ()
certeza você sabe que tudo o que Ruby considera um literal inteiro será aceito e todo o resto será rejeitado. Duplicar o que a linguagem já oferece é sem dúvida um cheiro de código pior do que usar exceções para controle.
Você pode fazer um forro:
str = ...
int = Integer(str) rescue nil
if int
int.times {|i| p i}
end
ou mesmo
int = Integer(str) rescue false
Dependendo do que você está tentando fazer, você também pode usar diretamente um bloco de término inicial com a cláusula de resgate:
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
, mas MatchData
casos enil
!!
ou use-o present?
se precisar de um valor booleano!!( "12".match /^(\d)+$/ )
ou "12".match(/^(\d)+$/).present?
(o último que requerem Rails / ActiveSupport)
O Ruby 2.6.0 permite a conversão para um número inteiro sem gerar uma exceção e retornará nil
se a conversão falhar. E, como a nil
maioria se comporta como false
no Ruby, você pode facilmente verificar um número inteiro 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_
. Acho isso bobo em métodos de questionmark, eu gosto "04".integer?
muito melhor do que "foo".is_integer?
."01"
e tal.integer?("a string")
ftl.
String#integer?
é o tipo de patch comum que todo codificador Ruby e seu primo gosta de adicionar à linguagem, levando a bases de código com três implementações sutilmente incompatíveis diferentes e quebra inesperada. Aprendi isso da maneira mais difícil em grandes projetos Ruby.
A maneira Melhor e Simples é 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
também é bom, mas retornará 0
paraInteger nil
Eu prefiro:
config / inicializadores / string.rb
class String
def number?
Integer(self).is_a?(Integer)
rescue ArgumentError, TypeError
false
end
end
e depois:
[218] pry(main)> "123123123".number?
=> true
[220] pry(main)> "123 123 123".gsub(/ /, '').number?
=> true
[222] pry(main)> "123 123 123".number?
=> false
ou verifique o número de telefone:
"+34 123 456 789 2".gsub(/ /, '').number?
Uma maneira muito mais simples poderia 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
Pessoalmente, gosto da abordagem de exceção, embora a torne um pouco mais concisa:
class String
def integer?(str)
!!Integer(str) rescue false
end
end
No entanto, como outros já declararam, isso não funciona com cadeias octais.
O Ruby 2.4 possui Regexp#match?
: (com um ?
)
def integer?(str)
/\A[+-]?\d+\z/.match? str
end
Para versões mais antigas do Ruby, existe Regexp#===
. E embora o uso direto do operador de igualdade de caso deva ser geralmente evitado, ele parece muito limpo aqui:
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
Isso pode não ser adequado para todos os casos usando simplesmente:
"12".to_i => 12
"blah".to_i => 0
também pode fazer para alguns.
Se for um número e não 0, ele retornará um número. Se retornar 0, será uma sequência ou 0.
"12blah".to_i => 12
. Isso pode causar alguns problemas em cenários estranhos.
Aqui está a minha solução:
# /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
E aqui está como funciona:
/^(\d)+$/
é uma expressão de expressão regular para encontrar dígitos em qualquer sequência. Você pode testar suas expressões e resultados de expressões regulares em http://rubular.com/ .IntegerRegex
para evitar alocação desnecessária de memória toda vez que o usamos no método.integer?
é um método interrogativo que deve retornar true
oufalse
.match
é um método na string que corresponde às ocorrências de acordo com a expressão regex especificada no argumento e retorna os valores correspondentes ou nil
.!!
converte o resultado do match
método em booleano equivalente.String
classe existente é o patch do macaco, que não altera nada nas funcionalidades existentes da String, mas apenas adiciona outro método nomeado integer?
em qualquer objeto String.Expandir a resposta do @ rado acima pode também usar uma declaração ternária para forçar o retorno de booleanos verdadeiros ou falsos sem o uso de double bangs. É verdade que a versão de dupla negação lógica é mais concisa, mas provavelmente mais difícil de ler para os iniciantes (como eu).
class String
def is_i?
self =~ /\A[-+]?[0-9]+\z/ ? true : false
end
end
Para casos mais generalizados (incluindo números com ponto decimal), você pode tentar o seguinte método:
def number?(obj)
obj = obj.to_s unless obj.is_a? String
/\A[+-]?\d+(\.[\d]+)?\z/.match(obj)
end
Você pode testar este método em uma sessão 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 uma explicação detalhada do regex envolvido aqui, confira este artigo do blog :)
obj.is_a? String
porque a String # to_s retornará automaticamente , o que eu acho que não requer muito processamento em comparação com a .is_a?
chamada. Dessa forma, você fará apenas uma chamada nesta linha em vez de uma ou duas. Além disso, você pode incluir diretamente !!
dentro do number?
método, porque por convenção, um nome de método que termina com ?
deve retornar um valor booleano. Saudações!
Não tenho certeza se isso aconteceu quando essa pergunta foi feita, mas para qualquer um que se deparar com este post, a maneira mais simples é:
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á com qualquer objeto.
"12".is_an_integer? == true
"not12".is_an_integer? == false
12.is_an_integer? == true