루비에서 안전한 정수 파싱
라는 문자열이 있으며 '123'
로 변환하고 싶습니다 123
.
나는 당신이 단순히 할 수 있다는 것을 알고 some_string.to_i
있지만 그것은로 변환 'lolipops'
합니다 0
. 이것은 내가 생각한 효과가 아닙니다. 멋지고 고통스러운 잘못된 것을 변환하려고 할 때 내 얼굴이 터지기를 원합니다 Exception
. 그렇지 않으면, 유효한 0
숫자와 전혀 숫자가 아닌 것을 구별 할 수 없습니다 .
편집 : 정규식 속임수없이 표준 방식을 찾고있었습니다.
루비에는이 기능이 내장되어 있습니다 :
Integer('1001') # => 1001
Integer('1001 nights')
# ArgumentError: invalid value for Integer: "1001 nights"
Joseph Pecoraro의 답변에서 언급했듯이 0x
16 진수 및 0b
2 진수로 시작하는 것과 같이 10 진수가 아닌 유효한 문자열 과 0으로 시작하는 더 까다로운 숫자를 8 진수로 구문 분석 할 수 있습니다.
Ruby 1.9.2는 기수에 대한 두 번째 인수 옵션을 추가하여 위의 문제를 피할 수 있습니다.
Integer('23') # => 23
Integer('0x23') # => 35
Integer('023') # => 19
Integer('0x23', 10)
# => #<ArgumentError: invalid value for Integer: "0x23">
Integer('023', 10) # => 23
이것은 작동 할 수 있습니다 :
i.to_i if i.match(/^\d+$/)
또한 현재 승인 된 솔루션이 16 진, 8 진 및 2 진 숫자 구문 분석에 미칠 수있는 영향에 유의하십시오.
>> Integer('0x15')
# => 21
>> Integer('0b10')
# => 2
>> Integer('077')
# => 63
루비에서 시작 0x
하거나 0X
16 진수 0b
이거나 0B
2 0
진수이며 8 진수입니다. 이것이 원하는 동작이 아닌 경우 문자열을 패턴과 먼저 일치하는지 확인하는 다른 솔루션과 결합 할 수 있습니다. 등 /\d+/
등 정규 표현식,
허용 된 솔루션의 또 다른 예기치 않은 동작 (1.8, 1.9 사용)은 다음과 같습니다.
>> Integer(:foobar)
=> 26017
>> Integer(:yikes)
=> 26025
전달되는 내용이 확실하지 않은 경우을 추가해야합니다 .to_s
.
Myron의 답변이 마음에 들지만 "더 이상 Java / C #을 사용하지 않으므로 상속을 다시는 사용하지 않습니다"라는 Ruby 질병으로 고통 받고 있습니다 . 클래스를 열면 위험에 처할 수 있으며 특히 Ruby의 핵심 라이브러리에 포함되어있을 때는 드물게 사용해야합니다 . 나는 그것을 사용하지 않는다고 말하지는 않지만 일반적으로 피하는 것이 쉽고 더 나은 옵션이 있습니다.
class IntegerInString < String
def initialize( s )
fail ArgumentError, "The string '#{s}' is not an integer in a string, it's just a string." unless s =~ /^\-?[0-9]+$/
super
end
end
그런 다음 숫자가 될 수있는 문자열을 사용하려면 수행중인 작업이 명확하고 핵심 클래스를 방해하지 않습니다.
n = IntegerInString.new "2"
n.to_i
# => 2
IntegerInString.new "blob"
ArgumentError: The string 'blob' is not an integer in a string, it's just a string.
You can add all sorts of other checks in the initialize, like checking for binary numbers etc. The main thing though, is that Ruby is for people and being for people means clarity. Naming an object via its variable name and its class name makes things much clearer.
I had to deal with this in my last project, and my implementation was similar, but a bit different:
class NotAnIntError < StandardError
end
class String
def is_int?
self =~ /^-?[0-9]+$/
end
def safe_to_i
return self.to_i if is_int?
raise NotAnIntError, "The string '#{self}' is not a valid integer.", caller
end
end
class Integer
def safe_to_i
return self
end
end
class StringExtensions < Test::Unit::TestCase
def test_is_int
assert "98234".is_int?
assert "-2342".is_int?
assert "02342".is_int?
assert !"+342".is_int?
assert !"3-42".is_int?
assert !"342.234".is_int?
assert !"a342".is_int?
assert !"342a".is_int?
end
def test_safe_to_i
assert 234234 == 234234.safe_to_i
assert 237 == "237".safe_to_i
begin
"a word".safe_to_i
fail 'safe_to_i did not raise the expected error.'
rescue NotAnIntError
# this is what we expect..
end
end
end
someString = "asdfasd123"
number = someString.to_i
if someString != number.to_s
puts "oops, this isn't a number"
end
Probably not the cleanest way to do it, but should work.
Re: Chris's answer
Your implementation let's things like "1a" or "b2" through. How about this instead:
def safeParse2(strToParse)
if strToParse =~ /\A\d+\Z/
strToParse.to_i
else
raise Exception
end
end
["100", "1a", "b2", "t"].each do |number|
begin
puts safeParse2(number)
rescue Exception
puts "#{number} is invalid"
end
end
This outputs:
100
1a is invalid
b2 is invalid
t is invalid
참고URL : https://stackoverflow.com/questions/49274/safe-integer-parsing-in-ruby
'Programing' 카테고리의 다른 글
캡처 한 그룹 만 바꾸는 방법? (0) | 2020.06.07 |
---|---|
슬래시를 이스케이프 처리하는 json_encode () (0) | 2020.06.07 |
C ++의 스택, 정적 및 힙 (0) | 2020.06.07 |
Javascript-문서가로드되었는지 감지하는 방법 (IE 7 / Firefox 3) (0) | 2020.06.07 |
Chrome에서 Selenium WebDriver 테스트 사례를 실행하는 방법은 무엇입니까? (0) | 2020.06.07 |