Rubyを使用して文字列が基本的に引用符内の整数であるかどうかをテストする方法


128

関数が必要ですis_an_integer

  • "12".is_an_integer? trueを返します。
  • "blah".is_an_integer? falseを返します。

Rubyでこれを行うにはどうすればよいですか?私は正規表現を書きますが、私が知らないこのためのヘルパーがいると思います。



1
正規表現に依存するソリューションの使用には注意してください。ベンチマークは、通常のコードよりも実行速度がはるかに遅いことを示しています。
Tin Man

回答:


135

正規表現を使用できます。@janmが提案する関数を以下に示します。

class String
    def is_i?
       !!(self =~ /\A[-+]?[0-9]+\z/)
    end
end

@wichからのコメントによる編集バージョン:

class String
    def is_i?
       /\A[-+]?\d+\z/ === self
    end
end

正の数だけをチェックする必要がある場合

  if !/\A\d+\z/.match(string_to_check)
      #Is not a positive number
  else
      #Is all good ..continue
  end  

4
悪くない。Rubyでは、関数の最後の式で戻り値が生成される場合、通常は「return」キーワードを省略します。これは整数値0も返します。おそらくブール値が必要なので、!!(str =〜/ ^ [-+]?[0-9] + $ /)のように実行します。次に、それを文字列に追加し、「str」の代わりに「self」を使用して引数を省略し、名前を「is_i?」に変更できます。...
janm 2009

2
ありがとう!ルビの慣習や慣行については、まったく手がかりがありません。Rubyと正規表現で簡単なグーグルを実行して構文を確認し、問題の問題に適用するように正規表現を変更してテストしました。それは実際にはかなりすっきりしている..私は私がより多くの余暇を持っているとき、私はそれをもっと長く見せる必要があるかもしれません。
ラドー

あなたは正しい考えを持っていますが、それはバイナリまたは16進数リテラルと一致しません(以下の編集済みソリューションを参照してください)。
サラ・メイ

16
2つのコメント。構成の/regexp/ === self代わりに使用できます!!(self =~ /regexp/)。あなたは、文字クラス「\ D」の代わりに使用することができます[0-9]
ウィッヒ

1
整数の最も単純な正規表現は、おそらく/ ^ \ d + $ /
keithxm23 '30

169

さて、ここに簡単な方法があります:

class String
  def is_integer?
    self.to_i.to_s == self
  end
end

>> "12".is_integer?
=> true
>> "blah".is_integer?
=> false

文字列を変換するために例外を引き起こすソリューションに同意しません-例外は制御フローではなく、あなたはそれを正しい方法で行うこともできます。とはいえ、上記の私の解決策は、基数10以外の整数を処理しません。だからここに例外に頼らずに行う方法があります:

  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

27
"01" .to_i.to_s!= "01"
sepp2k

2
に置き換えself.to_i.to_s == selfられInteger self rescue falseませんか?
メレディスL.パターソン

5
できますが、それは悪い形です。制御フローとして例外を使用しないでください。また、誰のコードにも「rescue false」(または「rescue true」)を含めないでください。いくつかの単純なgsubを使用すると、OPで指定されていないエッジケースでソリューションが機能します。
サラ・メイ

4
私は多くの人がそれを使用していることを知っています、そしてそれは確かに審美的に楽しいです。私にとっては、コードを再構築する必要があることを示しています。例外を予期している場合...それは例外ではありません。
サラ・メイ

2
例外を制御フローとして使用しないでください。私は、開発者向けの数値が認識されることが要件であるとは思いません。特に先行ゼロと8進数に関する混乱の可能性を考えると、バグと見なされる可能性があるプログラマー以外の状況で。to_iとも一致しません。コードは "-0123"ケースを処理しません。そのケースを処理したら、8進数用の個別の正規表現は必要ありません。「any?」を使用するだけで、さらに先に進むことができます。関数内の唯一のステートメントは、 "[/ re1 /、/ re2 /、/ re3 /] .any?{| re | self =〜re}"であり、if句やreturnはありません。
janm 2009

67

あなたはInteger(str)それが発生するかどうかを使用して見ることができます:

def is_num?(str)
  !!Integer(str)
rescue ArgumentError, TypeError
  false
end

これはに対してtrueを返しますが、有効な整数リテラル"01"ではないため"09"、に対してはtrueを返しません09。それが10目的の動作でない場合は、2番目の引数としてを追加できるIntegerため、数値は常に10を底として解釈されます。


39
おい...ただ数値を変換するために例外を引き起こす?例外は制御フローではありません。
サラ・メイ

29
そうではありませんが、残念ながら、これはRubyで文字列の「完全性」を判断するための標準的な方法です。#to_i許容性のため、使用するメソッドはあまりにも壊れています。
Avdi、2009

17
なぜだろうと不思議に思う人にとって、Integer( "09")は、 "0"で8進数になり、9は有効な8進数ではないため、無効です。osdir.com/ml/lang.ruby.general/2002-08/msg00247.html
Andrew Grimm

20
サラ:正規表現を使用できますが、整数(負の数、16進数、8進数、アンダースコア、たとえば1_000_000)を解析するときにRubyが行うすべてのケースを処理するためには、非常に大きな正規表現となり、間違いが起こりやすくなります。 Rubyが整数リテラルと見なすものはすべて受け入れられ、それ以外はすべて拒否されることを知っているInteger()ので、正規Integer ()です。言語がすでにあなたに与えているものを複製することは、おそらく制御のために例外を使用するよりも悪いコード臭です。
Avdi、2009

9
@Rado車輪を再発明しています。
sepp2k 2014年

24

あなたはワンライナーを行うことができます:

str = ...
int = Integer(str) rescue nil

if int
  int.times {|i| p i}
end

あるいは

int = Integer(str) rescue false

何をしようとしているのかに応じて、レスキュー句付きの開始終了ブロックを直接使用することもできます。

begin
  str = ...
  i = Integer(str)

  i.times do |j|
    puts j
  end
rescue ArgumentError
  puts "Not an int, doing something else"
end

1
「制御フローとしての例外」というトピックに関しては、現在のメソッドの使用方法がわからないため、例外が適合するかどうかを実際に判断することはできません。文字列が入力され、整数である必要がある場合、非整数を指定すると例外が発生します。ただし、処理は同じメソッドではなく、おそらくInteger(str).times {| i | puts i}または何でも。
Robert Klemme、

24
"12".match(/^(\d)+$/)      # true
"1.2".match(/^(\d)+$/)     # false
"dfs2".match(/^(\d)+$/)    # false
"13422".match(/^(\d)+$/)   # true

4
それは戻りませんtruefalseなく、MatchDataインスタンスとnil
ステファン・

それはそれが返すものではありませんが、一致する場合
Maciej Krasowski '

5
ブール値または(後者にはRails / activesupport が必要)が必要な場合は!!、ラップするか使用しpresent?ます!!( "12".match /^(\d)+$/ )"12".match(/^(\d)+$/).present?
mahemoff

1
この正規表現は符号を考慮していません。負の数も有効な整数です。あなたは今、有効なためにテストしている自然数またはゼロ。
Jochem Schulenklopper

13

Ruby 2.6.0では、例外を発生させることなく整数nilのキャストが可能で、キャストが失敗すると戻ります。そして、nilほとんどがfalseRubyのように動作するため、次のように整数を簡単にチェックできます。

if Integer(my_var, exception: false)
  # do something if my_var can be cast to an integer
end

8
class String
  def integer?
    Integer(self)
    return true
  rescue ArgumentError
    return false
  end
end
  1. プレフィックスは付きませんis_。私は次のように、questionmark法上のそれは愚かな私を見つける"04".integer?よりも良好たくさん"foo".is_integer?
  2. 通用するsepp2kによる実用的なソリューションを使用しています"01"
  3. オブジェクト指向、そう。

1
それを#integer?と命名するための+1、それを使用してStringを乱雑にするための-1 :-P
Avdi

1
他にどこに行きますか?integer?("a string")ftl。
8月のリリアス2009

2
String#integer?Rubyのすべてのコーダーとそのいとこが言語に追加することを好む種類の一般的なパッチであり、わずかに互換性のない3つの異なる実装と予期しない破損をコードベースにもたらします。大規模なRubyプロジェクトでこれを難しい方法で学びました。
Avdi 2009

上記と同じコメント:例外を制御フローに使用しないでください。
サラ・メイ

欠点:このソリューションは、1つのコンバージョンを無駄にしています。
Robert Klemme、2014年

7

最良でシンプルな方法は 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また良いですがそれはの0ために戻りますInteger nil


あなたの答えに気付いてよかった。それ以外の場合は、「Float」が必要なときに「Integer」を使用していたでしょう。
ジェフZivkovic

これは簡単ですが、最良の答えです!ほとんどの場合、Stringクラスへの特別なパッチは実際には必要ありません。これは私にとって最も効果的です!
Anh Nguyen

(Float(value)rescue false)?Float(value).to_s == value?Float(value):Integer(value):value
okliv

6

私は好む:

config / initializers / string.rb

class String
  def number?
    Integer(self).is_a?(Integer)
  rescue ArgumentError, TypeError
    false
  end
end

その後:

[218] pry(main)> "123123123".number?
=> true
[220] pry(main)> "123 123 123".gsub(/ /, '').number?
=> true
[222] pry(main)> "123 123 123".number?
=> false

または電話番号を確認してください:

"+34 123 456 789 2".gsub(/ /, '').number?

4

より簡単な方法は

/(\D+)/.match('1221').nil? #=> true
/(\D+)/.match('1a221').nil? #=> false
/(\D+)/.match('01221').nil? #=> true

3
  def isint(str)
    return !!(str =~ /^[-+]?[1-9]([0-9]*)?$/)
  end

コードのみの回答はあまり役に立ちません。代わりに、それがどのように機能するのか、なぜそれが適切な答えであるのかを説明してください。私たちは、解決策が理解されるように将来の教育を行い、当面の問題を解決するのではありません。
Tin Man

3

個人的に私は例外アプローチを気に入っていますが、少し簡潔にしています。

class String
  def integer?(str)
    !!Integer(str) rescue false
  end
end

ただし、他の人がすでに述べたように、これはOctal文字列では機能しません。


2

Ruby 2.4にはRegexp#match?(:付き?

def integer?(str)
  /\A[+-]?\d+\z/.match? str
end

古いRubyバージョンにはがありRegexp#===ます。また、大文字と小文字の等値演算子を直接使用することは一般的に避けられるべきですが、ここでは非常にきれいに見えます。

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

2

これは、単純に次のように使用するすべての場合に適しているとは限りません。

"12".to_i   => 12
"blah".to_i => 0

いくつかのためにもするかもしれません。

数値で0ではない場合は、数値を返します。0を返す場合は、文字列または0です。


11
動作しますが、は推奨されていません"12blah".to_i => 12。これは、奇妙なシナリオでいくつかの問題を引き起こす可能性があります。
rfsbraz

2

これが私の解決策です:

# /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

そして、それがどのように機能するかです:

  • /^(\d)+$/ある正規表現任意の文字列に数字を見つけるための式は。正規表現と結果はhttp://rubular.com/でテストできます。
  • IntegerRegexメソッドで使用するたびに不必要なメモリ割り当てを回避するために、定数に保存します。
  • integer?返す必要があります疑問方法ですtruefalse
  • match 引数の指定された正規表現に従って出現と一致し、一致した値を返す文字列のメソッドです。または nilです。
  • !! の結果を変換します matchメソッドを同等のブール値にます。
  • また、既存のStringクラスでメソッドを宣言することは、既存のString機能で何も変更せずinteger?、任意のStringオブジェクトで指定された別のメソッドを追加するだけの、モンキーパッチです。

1
これについて少し説明をお願いします。
stef

@stef-私は同じことをしました。ご不明な点がありましたらお知らせください。
Sachin

1

上記の@radoの回答を拡張すると、3項ステートメントを使用して、ダブルバンを使用せずにtrueまたはfalseのブール値を強制的に返すこともできます。確かに、二重論理否定バージョンはより簡潔ですが、おそらく(私のような)初心者には読みにくいでしょう。

class String
  def is_i?
     self =~ /\A[-+]?[0-9]+\z/ ? true : false
  end
end

正規表現を使用すると、Rubyはより多くの作業を強いられるので、これをループで使用すると、コードが遅くなることを考慮してください。式のアンカーは役立ちますが、正規表現は依然として大幅に遅くなります。
Tin Man

1

より一般的なケース(小数点付きの数値を含む)の場合は、次の方法を試すことができます。

def number?(obj)
  obj = obj.to_s unless obj.is_a? String
  /\A[+-]?\d+(\.[\d]+)?\z/.match(obj)
end

このメソッドは、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

ここに含まれる正規表現の詳細な説明については、このブログ記事をチェックしてください :)


String#to_sはそれ自体を返すobj.is_a? Stringため、呼び出す必要はありません。これは、呼び出しに比べてあまり多くの処理を必要としないと思います。この方法では、この行では1つまたは2つではなく1つだけ呼び出します。また、慣例により、で終わるメソッド名はブール値を返すことになっているため、メソッド内に直接含めることもできます。よろしく!.is_a?!!number??
Giovanni Benussi 2017年

-1

私は次のことが好きです。

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

ただし注意:

is_integer?('123sdfsdf')
=> true

-2

1つのライナー string.rb

def is_integer?; true if Integer(self) rescue false end

-3

この質問が出されたときにこれがあったかどうかはわかりませんが、この投稿を偶然見つけた人にとって、最も簡単な方法は次のとおりです。

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? 任意のオブジェクトで動作します。


それは元の質問が求めていることではありません。OPは、文字列が整数かどうかも知りたいと考えています。例 "12".is_an_integer? == true "not12".is_an_integer? == false 12.is_an_integer? == true
マークラー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.