Potrzebuję funkcji is_an_integer, gdzie
"12".is_an_integer?zwraca prawdę."blah".is_an_integer?zwraca false.
Jak mogę to zrobić w Rubim? Napisałbym wyrażenie regularne, ale zakładam, że istnieje pomocnik, którego nie jestem świadomy.
Potrzebuję funkcji is_an_integer, gdzie
"12".is_an_integer? zwraca prawdę."blah".is_an_integer? zwraca false.Jak mogę to zrobić w Rubim? Napisałbym wyrażenie regularne, ale zakładam, że istnieje pomocnik, którego nie jestem świadomy.
Odpowiedzi:
Możesz używać wyrażeń regularnych. Oto funkcja z sugestiami @ janm.
class String
def is_i?
!!(self =~ /\A[-+]?[0-9]+\z/)
end
end
Wersja zredagowana zgodnie z komentarzem z @wich:
class String
def is_i?
/\A[-+]?\d+\z/ === self
end
end
Jeśli potrzebujesz tylko sprawdzić liczby dodatnie
if !/\A\d+\z/.match(string_to_check)
#Is not a positive number
else
#Is all good ..continue
end
/regexp/ === selfzamiast !!(self =~ /regexp/)konstrukcji. Możesz użyć klasy znaków „\ d” zamiast[0-9]
Oto prosty sposób:
class String
def is_integer?
self.to_i.to_s == self
end
end
>> "12".is_integer?
=> true
>> "blah".is_integer?
=> false
Nie zgadzam się z rozwiązaniami, które prowokują wyjątek do konwersji łańcucha - wyjątki nie są sterowaniem przepływem i równie dobrze możesz zrobić to we właściwy sposób. To powiedziawszy, moje rozwiązanie powyżej nie dotyczy liczb całkowitych innych niż dziesiętne. Oto sposób na zrobienie tego bez uciekania się do wyjątków:
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 == selfz Integer self rescue false?
Możesz użyć Integer(str)i zobaczyć, czy podnosi:
def is_num?(str)
!!Integer(str)
rescue ArgumentError, TypeError
false
end
Należy zauważyć, że chociaż zwraca to prawdę dla "01", to nie dla "09", po prostu dlatego, 09że nie byłby prawidłowym literałem całkowitoliczbowym. Jeśli nie chcesz tego zachowania, możesz dodać 10jako drugi argument Integer, aby liczba była zawsze interpretowana jako podstawa 10.
#to_isą po prostu zbyt zepsute ze względu na ich pobłażliwość.
Integer()jest kanoniczne, ponieważ z Integer ()pewnością wiesz, że wszystko, co Ruby uzna za literał całkowity, zostanie zaakceptowane, a wszystko inne zostanie odrzucone. Powielanie tego, co już daje język, jest prawdopodobnie gorszym zapachem kodu niż używanie wyjątków do kontroli.
Możesz zrobić jedną wkładkę:
str = ...
int = Integer(str) rescue nil
if int
int.times {|i| p i}
end
lub nawet
int = Integer(str) rescue false
W zależności od tego, co próbujesz zrobić, możesz również bezpośrednio użyć bloku początku końca z klauzulą ratunkową:
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
truei falseale MatchDatainstancji inil
!!lub użyj, present?jeśli potrzebujesz boolean !!( "12".match /^(\d)+$/ )lub "12".match(/^(\d)+$/).present?(ten ostatni wymaga Rails /
Ruby 2.6.0 umożliwia rzutowanie na liczbę całkowitą bez zgłaszania wyjątku i zwraca, niljeśli rzutowanie się nie powiedzie. A ponieważ w nilwiększości zachowuje się jak falsew Rubim, możesz łatwo sprawdzić liczbę całkowitą, taką jak ta:
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_. Uważam to za głupie, jeśli chodzi o metody ze znakami zapytania, lubię "04".integer?dużo lepiej niż "foo".is_integer?."01"i takie.integer?("a string")ftl.
String#integer?to rodzaj powszechnej łatki, którą każdy programista Rubiego i ich kuzyn lubi dodawać do języka, co prowadzi do baz kodu z trzema różnymi, nieznacznie niekompatybilnymi implementacjami i nieoczekiwanymi awariami. Nauczyłem się tego na własnej skórze w dużych projektach Ruby.
Najlepszym i prostym sposobem jest użycie 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
Integerjest również dobre, ale powróci 0doInteger nil
Wolę:
config / initializers / string.rb
class String
def number?
Integer(self).is_a?(Integer)
rescue ArgumentError, TypeError
false
end
end
i wtedy:
[218] pry(main)> "123123123".number?
=> true
[220] pry(main)> "123 123 123".gsub(/ /, '').number?
=> true
[222] pry(main)> "123 123 123".number?
=> false
lub sprawdź numer telefonu:
"+34 123 456 789 2".gsub(/ /, '').number?
Mógłby być o wiele prostszy sposób
/(\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
Osobiście podoba mi się podejście wyjątkowe, chociaż chciałbym, aby było trochę bardziej zwięzłe:
class String
def integer?(str)
!!Integer(str) rescue false
end
end
Jednak, jak już powiedzieli inni, nie działa to z ciągami ósemkowymi.
Ruby 2.4 ma Regexp#match?: (z ?)
def integer?(str)
/\A[+-]?\d+\z/.match? str
end
W przypadku starszych wersji Ruby jest Regexp#===. I chociaż generalnie należy unikać bezpośredniego użycia operatora równości wielkości liter, wygląda to bardzo przejrzyście:
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
Może to nie być odpowiednie dla wszystkich przypadków, po prostu używając:
"12".to_i => 12
"blah".to_i => 0
może też zrobić dla niektórych.
Jeśli jest to liczba, a nie 0, zwróci liczbę. Jeśli zwraca 0, jest to ciąg znaków lub 0.
"12blah".to_i => 12. Może to powodować problemy w dziwnych scenariuszach.
Oto moje rozwiązanie:
# /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
A oto jak to działa:
/^(\d)+$/jest wyrażeniem regularnym służącym do znajdowania cyfr w dowolnym ciągu. Możesz przetestować swoje wyrażenia regularne i wyniki pod adresem http://rubular.com/ .IntegerRegexaby uniknąć niepotrzebnego przydziału pamięci za każdym razem, gdy używamy go w metodzie.integer?jest metodą pytającą, która powinna zwrócić truelub false.matchjest metodą na łańcuchu, która dopasowuje wystąpienia zgodnie z podanym wyrażeniem regularnym w argumencie i zwraca dopasowane wartości lub nil.!!konwertuje wynik matchmetody na równoważną wartość logiczną.Stringklasie jest małpą poprawką, która nie zmienia niczego w istniejących funkcjach String, ale po prostu dodaje inną metodę nazwaną integer?na dowolnym obiekcie String.Rozszerzając powyższą odpowiedź @ rado, można by również użyć trójskładnikowego stwierdzenia, aby wymusić powrót prawdziwych lub fałszywych wartości logicznych bez użycia podwójnej grzywki. To prawda, wersja z podwójną logiczną negacją jest bardziej zwięzła, ale prawdopodobnie trudniejsza do odczytania dla nowoprzybyłych (takich jak ja).
class String
def is_i?
self =~ /\A[-+]?[0-9]+\z/ ? true : false
end
end
W przypadku bardziej uogólnionych przypadków (w tym liczb z kropką dziesiętną) możesz wypróbować następującą metodę:
def number?(obj)
obj = obj.to_s unless obj.is_a? String
/\A[+-]?\d+(\.[\d]+)?\z/.match(obj)
end
Możesz przetestować tę metodę w sesji 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
Aby uzyskać szczegółowe wyjaśnienie związanego z tym wyrażenia regularnego, zapoznaj się z tym artykułem na blogu :)
obj.is_a? Stringponieważ ciąg # to_s zwróci się, co, jak sądzę, nie wymaga zbyt dużego przetwarzania w porównaniu z .is_a?wywołaniem. W ten sposób będziesz wykonywać tylko jedno połączenie w tej linii zamiast jednego lub dwóch. Można również umieścić bezpośrednio !!w number?metodzie, ponieważ zgodnie z konwencją nazwa metody kończąca się na ?ma zwracać wartość logiczną. Pozdrowienia!
Podoba mi się następujące, proste:
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
Uważaj jednak:
is_integer?('123sdfsdf')
=> true
Nie jestem pewien, czy tak było, gdy zadawano to pytanie, ale dla każdego, kto natknie się na ten post, najprostszym sposobem jest:
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? będzie działać z każdym przedmiotem.
"12".is_an_integer? == true "not12".is_an_integer? == false 12.is_an_integer? == true