Ruby를 사용하여 문자열이 기본적으로 따옴표로 묶인 정수인지 테스트하는 방법


128

함수가 필요합니다 is_an_integer.

  • "12".is_an_integer? true를 반환합니다.
  • "blah".is_an_integer? false를 반환합니다.

루비에서 어떻게해야합니까? 나는 정규 표현식을 작성하지만 내가 알지 못하는 도우미가 있다고 가정합니다.



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
나쁘지 않다. 루비에서는 함수의 마지막 표현식에서 반환 값이 생성되면 일반적으로 "return"키워드를 생략합니다. 이것은 또한 0의 정수 값을 리턴 할 것이고, 아마도 boolean을 원할 것이므로 !! (str = ~ / ^ [-+]? [0-9] + $ /)와 같이 할 것입니다. 그런 다음 문자열에 추가하고 "str"대신 "self"를 사용하여 인수를 생략 한 다음 이름을 "is_i?"로 변경할 수 있습니다. ...
janm

2
감사! 나는 루비 관습과 관행에 대한 단서가 없습니다. 나는 루비와 정규 표현식에 대해 빠른 구글을 수행하여 구문을보고, 문제에 적용되도록 정규 표현식을 변경하고 테스트했습니다. 실제로 꽤 깔끔합니다 .. 더 많은 여가 시간이있을 때 더 길게 보이게해야 할 수도 있습니다.
Rado

올바른 아이디어를 얻었지만 바이너리 또는 16 진수 리터럴과 일치하지 않습니다 (아래의 편집 된 솔루션 참조).
사라 메이

16
두 의견. 구문 /regexp/ === self대신 사용할 수 있습니다 !!(self =~ /regexp/). 당신은 문자 클래스 '\ D'대신 사용할 수 있습니다[0-9]
느릅 나무

1
정수에 대한 가장 간단한 정규식은 아마도 / ^ \ d + $ /
keithxm23

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?
Meredith L. Patterson

5
당신은 할 수 있지만, 그것은 나쁜 형태 일 것입니다. 예외를 제어 흐름으로 사용하지 않으며 코드에 "rescue false"(또는 "rescue true")를 포함해서는 안됩니다. 몇 가지 간단한 gsub'ing은 OP에 의해 지정되지 않은 엣지 케이스에 대한 솔루션을 작동하게합니다.
Sarah Mei

4
나는 많은 사람들이 그것을 사용한다는 것을 알고 있으며, 그것은 미적으로 기쁘게 생각합니다. 나에게 그것은 코드 구조 조정이 필요하다는 표시입니다. 예외가 예상되는 경우 ... 예외가 아닙니다.
사라 메이

2
예외를 제어 흐름으로 사용해서는 안된다는 데 동의합니다. 요구 사항이 개발자 중심의 숫자를 인식해야한다고 생각하지 않습니다. 프로그래머가 아닌 상황에서는 특히 0과 8 진을 혼동 할 수있는 버그를 감안할 때 버그로 볼 수 있습니다. 또한 to_i와 일치하지 않습니다. 코드가 "-0123"케이스를 처리하지 않습니다. 이 경우를 처리하면 8 진에 대해 별도의 정규 표현식이 필요하지 않습니다. "any?"를 사용하여 간단히 추가 할 수 있습니다. 함수의 유일한 문장은 "[/ re1 /, / re2 /, / re3 /] .any? {| re | self = ~ re}"일 수 있으며 if 절이나 반환 값은 없습니다.
janm

67

사용 Integer(str)하고 발생하는지 확인할 수 있습니다 .

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

이것은에 대해 true를 반환하지만 , 유효한 정수 리터럴이 아니기 때문에에 "01"대해 true를 반환 하지 않습니다 . 이것이 원하는 동작이 아닌 경우 에 두 번째 인수로 추가 할 수 있으므로 숫자는 항상 기본 10으로 해석됩니다."09"0910Integer


39
야 ... 수를 변환하기 위해 예외를 유발? 예외는 제어 흐름이 아닙니다.
Sarah Mei

29
그것들은 아니지만 불행히도 이것은 루비에서 문자열의 "정수"를 결정하는 정식 방법입니다. 허용 방법으로 #to_i인해 사용 하는 메소드 가 너무 손상되었습니다.
Avdi

17
왜 그런지 궁금해하는 사람들에게는 Integer ( "09")는 유효하지 않습니다. "0"은 8 진수이고 9는 유효한 8 진수가 아닙니다. osdir.com/ml/lang.ruby.general/2002-08/msg00247.html
Andrew Grimm

20
Sarah : 정규식을 사용할 수 있지만 루비가 정수 (음수, 16 진수, 8 진수, 밑줄 (예 : 1_000_000)를 구문 분석 할 때 수행하는 모든 경우를 처리하기 위해 매우 큰 정규식이며 잘못되기 쉽습니다. 루비가 정수 리터럴로 간주하는 것은 받아 들여지고 다른 모든 것은 거부된다는 것을 확실히 알기 Integer()때문에 표준 Integer ()입니다. 언어가 이미 제공 한 것을 복제하는 것은 제어를 위해 예외를 사용하는 것보다 더 나쁜 코드 냄새 일 것입니다.
Avdi

9
@Rado 그래서 바퀴를 재발 명하고 있습니다.
sepp2k

24

하나의 라이너를 사용할 수 있습니다.

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

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

또는

int = Integer(str) rescue false

수행하려는 작업에 따라 rescue 절과 함께 begin end block을 직접 사용할 수도 있습니다.

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 | 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
이 정규식은 부호를 고려하지 않습니다. 음수는 유효한 정수입니다 . 이제 유효한 자연수 또는 0을 테스트하고 있습니다.
Jochem Schulenklopper

13

Ruby 2.6.0 에서는 예외를 발생시키지 않고 정수로nil 캐스트 할 수 있으며 캐스트가 실패하면 리턴 됩니다. 그리고 nil대부분 false루비 처럼 동작 하기 때문에 다음과 같이 쉽게 정수를 확인할 수 있습니다 :

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 방법에 대한 그 바보 I을 찾아 "04".integer?더 나은보다 훨씬 "foo".is_integer?.
  2. sepp2k의 합리적인 솔루션을 사용합니다 "01".
  3. 객체 지향, 예.

1
이름을 +1로 지정하면 +1 ?, 문자열로 어수선하게 -1
:-P

1
다른 곳은 어디입니까? integer?("a string")ftl.
August Lilleaas

2
String#integer?모든 Ruby 코더와 그 사촌이 언어에 추가하는 것을 좋아하는 공통 패치의 일종으로, 세 가지 미묘하게 호환되지 않는 구현과 예기치 않은 손상이있는 코드베이스로 이어집니다. 나는 큰 루비 프로젝트에서 이것을 어려운 방법으로 배웠다.
Avdi

위와 동일한 설명 : 제어 흐름에는 예외를 사용해서는 안됩니다.
Sarah Mei

단점 :이 솔루션은 하나의 변환을 낭비하고 있습니다.
Robert Klemme

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"를 사용했을 것입니다.
제프 지크 코 비치

이것은 간단하지만 가장 좋은 대답입니다! 대부분의 경우 String 클래스에 멋진 패치가 필요하지 않습니다. 이것은 나를 위해 가장 잘 작동합니다!
Anh Nguyen

(float (value) rescue false)? 플로트 (값) .to_s == 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

그러나 다른 사람들이 이미 언급했듯이 이것은 8 진수 문자열에서는 작동하지 않습니다.


2

루비 2.4 갖는다 Regexp#match?: (a 함께 ?)

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

이전 루비 버전에는이 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 2016 년

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?돌려 의문 방법 true또는 false.
  • match 인수의 주어진 정규 표현식에 따라 발생을 일치시키고 일치하는 값을 반환하는 문자열의 메소드입니다. nil .
  • !!match메소드 의 결과 를 동등한 부울로 변환합니다 .
  • 그리고 기존 String클래스 에서 메소드를 선언하는 것은 원숭이 패치입니다. 이것은 기존 문자열 기능에서 아무것도 변경하지 않지만 integer?String 객체에 이름이 지정된 다른 메소드를 추가 합니다.

1
이것에 약간의 설명을 추가해 주시겠습니까?
stef

@stef-나는 똑같이했다. 여전히 궁금한 점이 있으면 알려주세요.
Sachin

1

위의 @rado의 대답을 확장하면 삼중 문을 사용하여 더블 뱅을 사용하지 않고 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하기 때문에 호출 할 필요가 없으므로 호출에 비해 너무 많은 처리가 필요하지 않습니다 . 이 방법으로이 회선에서 하나 또는 두 개 대신 한 번만 전화를 겁니다. 또한 규칙으로 끝나는 메소드 이름 은 부울 값을 리턴해야하기 때문에 메소드 내부에 직접 포함시킬 수 있습니다 . 문안 인사! .is_a?!!number??
Giovanni Benussi

-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

하나의 라이너 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
Marklar
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.