내 응용 프로그램 컨트롤러에 다음이 있습니다.
def is_number?(object)
true if Float(object) rescue false
end
내 컨트롤러의 다음 조건 :
if mystring.is_number?
end
조건에서 undefined method
오류가 발생합니다. 내가 is_number
잘못 정의한 것 같은데 ...?
내 응용 프로그램 컨트롤러에 다음이 있습니다.
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
to_f
위의 내용 이 없으며 Float ()는 해당 동작을 나타내지 않습니다. Float("330.346.11")
raisesArgumentError: invalid value for Float(): "330.346.11"
lib/core_ext/string.rb
.
is_number?(string)
비트가 Ruby 1.9에서 작동 하지 않는다고 생각합니다 . Rails 또는 1.8의 일부일까요? String.is_a?(Numeric)
공장. stackoverflow.com/questions/2095493/… 도 참조하십시오 .
다음은이 문제를 해결하는 일반적인 방법에 대한 벤치 마크입니다. 어느 것을 사용해야할지는 예상되는 잘못된 사례의 비율에 따라 달라질 수 있습니다.
성능이 중요하지 않은 경우 원하는 것을 사용하십시오. :-)
# 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
/^\d+$/
Ruby에서 안전한 정규 표현식이 아닙니다 /\A\d+\Z/
. (예 : "42 \ n 일부 텍스트"반환 true
)
/^\d+$/
줄을 다룰 때 사용하는 것이 안전 하지만이 경우 문자열의 시작과 끝에 관한 것이므로 /\A\d+\Z/
.
발생한 예외에 의존하는 것은 가장 빠르고 읽기 쉽고 신뢰할 수있는 솔루션이 아닙니다.
다음을 수행합니다.
my_string.should =~ /^[0-9]+$/
expect(my_string).to match(/^[0-9]+$/)
my_string =~ /\A-?(\d+)?\.?\d+\Z/
'.1', '-0.1', '12'는 할 수 있지만 '', '-'또는 '.'
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
object = "1.2e+35"; object.to_f.to_s == object
그리고 일
아니 당신은 그것을 잘못 사용하고 있습니다. 당신의 is_number? 논쟁이 있습니다. 당신은 논쟁없이 그것을 불렀다
is_number를해야합니까? (mystring)
mystring
문자열이 참으로, mystring.is_a?(Integer)
항상 false가 될 것입니다. 그는 다음과 같은 결과를 원하는 것 같습니다is_number?("12.4") #=> true
Tl; dr : 정규식 접근 방식을 사용합니다. 수용된 답변의 구조 접근 방식보다 39 배 빠르며 "1,000"과 같은 사례도 처리합니다.
def regex_is_number? string
no_commas = string.gsub(',', '')
matches = no_commas.match(/-?\d+(?:\.\d+)?/)
if !matches.nil? && matches.size == 1 && matches[0] == no_commas
true
else
false
end
end
-
@Jakob S의 대답은 대부분 작동하지만 예외 포착은 정말 느릴 수 있습니다. 또한 구조 접근 방식은 "1,000"과 같은 문자열에서 실패합니다.
메서드를 정의 해 보겠습니다.
def rescue_is_number? string
true if Float(string) rescue false
end
def regex_is_number? string
no_commas = string.gsub(',', '')
matches = no_commas.match(/-?\d+(?:\.\d+)?/)
if !matches.nil? && matches.size == 1 && matches[0] == no_commas
true
else
false
end
end
이제 몇 가지 테스트 사례 :
test_cases = {
true => ["5.5", "23", "-123", "1,234,123"],
false => ["hello", "99designs", "(123)456-7890"]
}
그리고 테스트 케이스를 실행하기위한 약간의 코드 :
test_cases.each do |expected_answer, cases|
cases.each do |test_case|
if rescue_is_number?(test_case) != expected_answer
puts "**rescue_is_number? got #{test_case} wrong**"
else
puts "rescue_is_number? got #{test_case} right"
end
if regex_is_number?(test_case) != expected_answer
puts "**regex_is_number? got #{test_case} wrong**"
else
puts "regex_is_number? got #{test_case} right"
end
end
end
다음은 테스트 케이스의 출력입니다.
rescue_is_number? got 5.5 right
regex_is_number? got 5.5 right
rescue_is_number? got 23 right
regex_is_number? got 23 right
rescue_is_number? got -123 right
regex_is_number? got -123 right
**rescue_is_number? got 1,234,123 wrong**
regex_is_number? got 1,234,123 right
rescue_is_number? got hello right
regex_is_number? got hello right
rescue_is_number? got 99designs right
regex_is_number? got 99designs right
rescue_is_number? got (123)456-7890 right
regex_is_number? got (123)456-7890 right
몇 가지 성능 벤치 마크를 수행 할 시간 :
Benchmark.ips do |x|
x.report("rescue") { test_cases.values.flatten.each { |c| rescue_is_number? c } }
x.report("regex") { test_cases.values.flatten.each { |c| regex_is_number? c } }
x.compare!
end
결과 :
Calculating -------------------------------------
rescue 128.000 i/100ms
regex 4.649k i/100ms
-------------------------------------------------
rescue 1.348k (±16.8%) i/s - 6.656k
regex 52.113k (± 7.8%) i/s - 260.344k
Comparison:
regex: 52113.3 i/s
rescue: 1347.5 i/s - 38.67x slower
5.4e-29
. 나는 당신의 정규식이 그것들을 수용하도록 조정할 수 있다고 생각합니다.
Rails 4에서는 require File.expand_path('../../lib', __FILE__) + '/ext/string'
config / application.rb 를 입력해야
합니다.
논리의 일부로 예외를 사용하지 않으려면 다음을 시도 할 수 있습니다.
class String
def numeric?
!!(self =~ /^-?\d+(\.\d*)?$/)
end
end
모든 객체 클래스에서 작동하도록하려는 경우 또는 교체 class String
와 함께 class Object
문자열로 변환 자기 : !!(self.to_s =~ /^-?\d+(\.\d*)?$/)
nil?
당신은 그냥 할 수 있도록 제로 루비에 trurthy이며,!!(self =~ /^-?\d+(\.\d*)?$/)
!!
확실히하는 것은 작동합니다. 적어도 하나의 루비 스타일 가이드 ( github.com/bbatsov/ruby-style-guide )는 가독성 !!
을 .nil?
위해 피하는 것을 제안 했지만 !!
인기있는 리포지토리에서 사용 된 것을 보았고 부울로 변환하는 좋은 방법이라고 생각합니다. 나는 대답을 편집했습니다.
다음 기능을 사용하십시오.
def is_numeric? val
return val.try(:to_f).try(:to_s) == val
end
그래서,
is_numeric? "1.2f"
= 거짓
is_numeric? "1.2"
= 참
is_numeric? "12f"
= 거짓
is_numeric? "12"
= 참
"0"
. 또한이 메서드 .try
는 Ruby 핵심 라이브러리의 일부가 아니며 ActiveSupport를 포함하는 경우에만 사용할 수 있습니다.
"12"
질문의 네 번째 예는 잘못되었습니다. "12.10"
그리고 "12.00"
실패합니다.
이 솔루션은 얼마나 멍청합니까?
def is_number?(i)
begin
i+0 == i
rescue TypeError
false
end
end