[ruby-on-rails] Ruby on Rails에서 문자열이 숫자인지 테스트

내 응용 프로그램 컨트롤러에 다음이 있습니다.

def is_number?(object)
  true if Float(object) rescue false
end

내 컨트롤러의 다음 조건 :

if mystring.is_number?

end

조건에서 undefined method오류가 발생합니다. 내가 is_number잘못 정의한 것 같은데 …?



답변

생성 is_number?방법.

도우미 메서드를 만듭니다.

def is_number? string
  true if Float(string) rescue false
end

그리고 다음과 같이 부릅니다.

my_string = '12.34'

is_number?( my_string )
# => true

String클래스 확장 .

is_number?도우미 함수에 매개 변수로 전달하는 대신 문자열에서 직접 호출 할 수 있도록하려면 다음 과 같이 클래스 is_number?의 확장으로 정의해야합니다 String.

class String
  def is_number?
    true if Float(self) rescue false
  end
end

그리고 다음과 같이 호출 할 수 있습니다.

my_string.is_number?
# => true


답변

다음은이 문제를 해결하는 일반적인 방법에 대한 벤치 마크입니다. 어느 것을 사용해야할지는 예상되는 잘못된 사례의 비율에 따라 달라질 수 있습니다.

  1. 상대적으로 드문 경우 캐스팅이 확실히 가장 빠릅니다.
  2. 잘못된 경우가 흔하고 int 만 확인하는 경우 비교 대 변환 된 상태가 좋은 옵션입니다.
  3. 잘못된 경우가 흔하고 float를 확인하는 경우 regexp가 아마도 갈 길일 것입니다.

성능이 중요하지 않은 경우 원하는 것을 사용하십시오. 🙂

정수 검사 세부 사항 :

# 1.9.3-p448
#
# Calculating -------------------------------------
#                 cast     57485 i/100ms
#            cast fail      5549 i/100ms
#                 to_s     47509 i/100ms
#            to_s fail     50573 i/100ms
#               regexp     45187 i/100ms
#          regexp fail     42566 i/100ms
# -------------------------------------------------
#                 cast  2353703.4 (±4.9%) i/s -   11726940 in   4.998270s
#            cast fail    65590.2 (±4.6%) i/s -     327391 in   5.003511s
#                 to_s  1420892.0 (±6.8%) i/s -    7078841 in   5.011462s
#            to_s fail  1717948.8 (±6.0%) i/s -    8546837 in   4.998672s
#               regexp  1525729.9 (±7.0%) i/s -    7591416 in   5.007105s
#          regexp fail  1154461.1 (±5.5%) i/s -    5788976 in   5.035311s

require 'benchmark/ips'

int = '220000'
bad_int = '22.to.2'

Benchmark.ips do |x|
  x.report('cast') do
    Integer(int) rescue false
  end

  x.report('cast fail') do
    Integer(bad_int) rescue false
  end

  x.report('to_s') do
    int.to_i.to_s == int
  end

  x.report('to_s fail') do
    bad_int.to_i.to_s == bad_int
  end

  x.report('regexp') do
    int =~ /^\d+$/
  end

  x.report('regexp fail') do
    bad_int =~ /^\d+$/
  end
end

플로트 검사 세부 정보 :

# 1.9.3-p448
#
# Calculating -------------------------------------
#                 cast     47430 i/100ms
#            cast fail      5023 i/100ms
#                 to_s     27435 i/100ms
#            to_s fail     29609 i/100ms
#               regexp     37620 i/100ms
#          regexp fail     32557 i/100ms
# -------------------------------------------------
#                 cast  2283762.5 (±6.8%) i/s -   11383200 in   5.012934s
#            cast fail    63108.8 (±6.7%) i/s -     316449 in   5.038518s
#                 to_s   593069.3 (±8.8%) i/s -    2962980 in   5.042459s
#            to_s fail   857217.1 (±10.0%) i/s -    4263696 in   5.033024s
#               regexp  1383194.8 (±6.7%) i/s -    6884460 in   5.008275s
#          regexp fail   723390.2 (±5.8%) i/s -    3613827 in   5.016494s

require 'benchmark/ips'

float = '12.2312'
bad_float = '22.to.2'

Benchmark.ips do |x|
  x.report('cast') do
    Float(float) rescue false
  end

  x.report('cast fail') do
    Float(bad_float) rescue false
  end

  x.report('to_s') do
    float.to_f.to_s == float
  end

  x.report('to_s fail') do
    bad_float.to_f.to_s == bad_float
  end

  x.report('regexp') do
    float =~ /^[-+]?[0-9]*\.?[0-9]+$/
  end

  x.report('regexp fail') do
    bad_float =~ /^[-+]?[0-9]*\.?[0-9]+$/
  end
end


답변

class String
  def numeric?
    return true if self =~ /\A\d+\Z/
    true if Float(self) rescue false
  end
end

p "1".numeric?  # => true
p "1.2".numeric? # => true
p "5.4e-29".numeric? # => true
p "12e20".numeric? # true
p "1a".numeric? # => false
p "1.2.3.4".numeric? # => false


답변

발생한 예외에 의존하는 것은 가장 빠르고 읽기 쉽고 신뢰할 수있는 솔루션이 아닙니다.
다음을 수행합니다.

my_string.should =~ /^[0-9]+$/


답변

Ruby 2.6.0부터 숫자 형 캐스트 ​​메소드에는 선택적 exception-argument [1]이 있습니다. 이를 통해 예외를 제어 흐름으로 사용하지 않고 내장 메서드를 사용할 수 있습니다.

Float('x') # => ArgumentError (invalid value for Float(): "x")
Float('x', exception: false) # => nil

따라서 자신 만의 방법을 정의 할 필요없이 직접 변수를 확인할 수 있습니다.

if Float(my_var, exception: false)
  # do something if my_var is a float
end


답변

이게 내가하는 방법이지만 더 나은 방법이있을 것 같아

object.to_i.to_s == object || object.to_f.to_s == object


답변

아니 당신은 그것을 잘못 사용하고 있습니다. 당신의 is_number? 논쟁이 있습니다. 당신은 논쟁없이 그것을 불렀다

is_number를해야합니까? (mystring)