Não é ruim. Em Ruby, você geralmente omite a palavra-chave "return" se o valor de retorno for gerado na última expressão na função. Isso também retornará um valor inteiro zero, você provavelmente desejará um booleano, então algo como !! (str = ~ / ^ [- +]? [0-9] + $ /) faria isso. Em seguida, você pode adicioná-lo a String e deixar de fora o argumento, usando "self" em vez de "str" e alterando o nome para "is_i?" ...
JANM
2
Obrigado! Não tenho absolutamente nenhuma pista sobre convenções e práticas de rubi. Acabei de fazer um rápido google no ruby e expressões regulares para ver a sintaxe, alterei o regex para aplicar ao problema em questão e o testei. Na verdade, é bem legal. Talvez eu precise dar uma olhada mais longa quando tiver mais tempo livre.
Rado
Você tem a idéia certa, mas ela não corresponde aos literais binários ou hexadecimais (veja minha solução editada abaixo).
242 Sarah Mei
16
Dois comentários Você pode usar em /regexp/ === selfvez da !!(self =~ /regexp/)construção. Você pode usar a classe de caracteres '\ d' em vez de[0-9]
que
1
A regex simples para um inteiro provavelmente é / ^ \ d + $ /
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:
classStringdef 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|returntrueifself=~ match_pattern
endreturnfalseendend
Você poderia, mas isso seria uma má forma. Você não usa exceções como fluxo de controle, e o código de ninguém deve conter "resgate falso" (ou "resgate verdadeiro"). Algum gsub'ing simples faria minha solução funcionar para casos extremos não especificados pelo OP.
242 Sarah Mei
4
Eu sei que muitas pessoas usam, e é certamente esteticamente agradável. Para mim, porém, é uma indicação de que o código precisa de reestruturação. Se você está esperando uma exceção ... não é uma exceção.
242 Sarah Mei
2
Concordo que exceções não devem ser usadas como fluxo de controle. Não acho que o requisito seja que os números orientados ao desenvolvedor sejam reconhecidos. Em situações não programadoras, isso pode ser visto como um bug, principalmente devido à possível confusão em torno de zeros à esquerda e octal. Também não é consistente com to_i. Seu código não lida com o caso "-0123". Depois de lidar com esse caso, você não precisa de um regexp separado para octal. Você pode simplesmente continuar usando "any?". A única instrução em sua função pode ser "[/ re1 /, / re2 /, / re3 /]. Qualquer um? {| Re | self = ~ re}", sem cláusulas ou retornos if.
Deve-se ressaltar que, embora isso retorne true para "01", não retorna "09", simplesmente porque 09não seria um literal inteiro válido. Se esse não é o comportamento que você deseja, você pode adicionar 10como um segundo argumento para Integerque o número seja sempre interpretado como base 10.
Cara ... provocando uma exceção só para converter um número? Exceções não são fluxo de controle.
Sarah Mei
29
Eles não são, mas infelizmente essa é a maneira canônica de determinar a "integridade" de uma string no Ruby. Métodos usando #to_isão muito quebrados por causa de sua permissividade.
Sarah: você pode usar um Regex, mas para lidar com todos os casos que Ruby faz ao analisar números inteiros (números negativos, hex, octal, sublinhados, por exemplo, 1_000_000), seria um Regex muito grande e fácil de se errar. 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.
Avdi
9
@Rado Então, é reinventar a roda.
sepp2k
24
Você pode fazer um forro:
str =...
int =Integer(str)rescuenilif int
int.times {|i| p i}end
ou mesmo
int =Integer(str)rescuefalse
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
endrescueArgumentError
puts "Not an int, doing something else"end
Com relação ao tópico "exceção como fluxo de controle": como não sabemos como o método em questão deve ser usado, não podemos realmente julgar se as exceções se encaixariam ou não. Se a sequência for inserida e for necessário que seja um número inteiro, fornecer um número inteiro não justificaria uma exceção. Embora, então, talvez o tratamento não esteja no mesmo método e provavelmente faríamos apenas Integer (str) .times {| i | coloca i} ou o que quer.
Envolva-o !!ou use-o present?se precisar de um valor booleano!!( "12".match /^(\d)+$/ ) ou "12".match(/^(\d)+$/).present?(o último que requerem Rails / ActiveSupport)
mahemoff
1
Essa expressão regular não leva em consideração o sinal: números negativos também são números inteiros válidos . Agora você está testando números naturais válidos ou zero.
+1 por nome #integer ?, -1 por desordenar String com ele :-P
Avdi
1
Para onde mais iria? integer?("a string")ftl.
August Lilleaas
2
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.
Avdi
O mesmo comentário acima: as exceções não devem ser usadas para o fluxo de controle.
Sarah Mei
Desvantagem: esta solução está desperdiçando uma conversão.
Robert Klemme 31/01
7
A maneira Melhor e Simples é usar Float
val =Float"234"rescuenilFloat"234"rescuenil#=> 234.0Float"abc"rescuenil#=> nilFloat"234abc"rescuenil#=> nilFloatnilrescuenil#=> nilFloat""rescuenil#=> nil
Integertambém é bom, mas retornará 0paraInteger nil
Estou feliz por ter notado sua resposta. Caso contrário, eu teria optado por "Inteiro" quando precisar de "Flutuar".
Jeff Zivkovic
Isso é simples, mas a melhor resposta! Na verdade, não precisamos de um patch sofisticado para a classe String na maioria dos casos. Isso funciona melhor para mim!
As respostas apenas de código não são muito úteis. Em vez disso, forneça uma explicação de como funciona e por que é a resposta apropriada. Queremos educar para o futuro, para que a solução seja entendida, e não para resolver a questão imediata.
o homem de lata
3
Pessoalmente, gosto da abordagem de exceção, embora a torne um pouco mais concisa:
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:
/^(\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/ .
Nós o salvamos de forma constante 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 trueoufalse .
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 matchmétodo em booleano equivalente.
E declarar o método na Stringclasse 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.
Você poderia adicionar uma pequena explicação para isso, por favor?
stef 24/05
@stef - Eu fiz o mesmo. Entre em contato se você ainda tiver alguma dúvida.
Sachin 25/05
1
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).
Considere que o uso de expressões regulares força o Ruby a fazer muito mais trabalho; portanto, se isso for usado em loop, o código ficará lento. Ancorar a expressão ajuda, mas o regex ainda é significativamente mais lento.
o homem de lata
1
Para casos mais generalizados (incluindo números com ponto decimal), você pode tentar o seguinte método:
Não é necessário chamar obj.is_a? Stringporque 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 é isso que a pergunta original está fazendo. O OP quer saber se a sequência também é um número inteiro. por exemplo "12".is_an_integer? == true"not12".is_an_integer? == false12.is_an_integer? == true
Respostas:
Você pode usar expressões regulares. Aqui está a função com as sugestões de @ janm.
Uma versão editada de acordo com o comentário de @wich:
Caso você precise apenas verificar números positivos
fonte
/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:
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:
fonte
self.to_i.to_s == self
comInteger self rescue false
?Você pode usar
Integer(str)
e ver se isso gera:Deve-se ressaltar que, embora isso retorne true para
"01"
, não retorna"09"
, simplesmente porque09
não seria um literal inteiro válido. Se esse não é o comportamento que você deseja, você pode adicionar10
como um segundo argumento paraInteger
que o número seja sempre interpretado como base 10.fonte
#to_i
são muito quebrados por causa de sua permissividade.Integer()
é canônico, porque comInteger ()
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:
ou mesmo
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:
fonte
fonte
true
efalse
, masMatchData
casos enil
!!
ou use-opresent?
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 anil
maioria se comporta comofalse
no Ruby, você pode facilmente verificar um número inteiro como este:fonte
is_
. Acho isso bobo em métodos de questionmark, eu gosto"04".integer?
muito melhor do que"foo".is_integer?
."01"
e tal.fonte
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
Integer
também é bom, mas retornará0
paraInteger nil
fonte
Eu prefiro:
config / inicializadores / string.rb
e depois:
ou verifique o número de telefone:
fonte
Uma maneira muito mais simples poderia ser
fonte
fonte
Pessoalmente, gosto da abordagem de exceção, embora a torne um pouco mais concisa:
No entanto, como outros já declararam, isso não funciona com cadeias octais.
fonte
O Ruby 2.4 possui
Regexp#match?
: (com um?
)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:fonte
Isso pode não ser adequado para todos os casos usando simplesmente:
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.
fonte
"12blah".to_i => 12
. Isso pode causar alguns problemas em cenários estranhos.Aqui está a minha solução:
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 retornartrue
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 ounil
.!!
converte o resultado domatch
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 nomeadointeger?
em qualquer objeto String.fonte
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).
fonte
Para casos mais generalizados (incluindo números com ponto decimal), você pode tentar o seguinte método:
Você pode testar este método em uma sessão irb:
Para uma explicação detalhada do regex envolvido aqui, confira este artigo do blog :)
fonte
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 donumber?
método, porque por convenção, um nome de método que termina com?
deve retornar um valor booleano. Saudações!Eu gosto do seguinte, direto:
Cuidado, porém:
fonte
Um forro em
string.rb
fonte
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 é:
.is_a?
funcionará com qualquer objeto.fonte
"12".is_an_integer? == true
"not12".is_an_integer? == false
12.is_an_integer? == true