source

Ruby에서 안전한 정수 구문 분석

manycodes 2023. 6. 20. 21:44
반응형

Ruby에서 안전한 정수 구문 분석

저는 있어이요, 게봐해말,▁say라고 하는 요.'123'로 변환하고 .123.

당신이 간단히 할 수 있다는 것을 압니다.some_string.to_i하지만 그것은 변환됩니다.'lolipops'0그건 제가 염두에 두고 있는 효과가 아닙니다.나는 내가 뭔가 잘못된 것을 전환하려고 할 때, 멋지고 고통스럽게 그것이 내 얼굴에서 폭발하기를 원합니다.Exception않으면 ▁a▁▁betweenish다▁otherwise니없습▁i'를 구별할 수 없습니다.0그리고 숫자가 전혀 아닌 것.

편집: 저는 정규식 속임수 없이 표준적인 방법을 찾고 있었습니다.

Ruby에는 다음과 같은 기능이 내장되어 있습니다.

Integer('1001')                                    # => 1001  
Integer('1001 nights')  
# ArgumentError: invalid value for Integer: "1001 nights"  

Joseph Pecoraro의 답변에서 언급했듯이, 다음과 같이 십진수가 아닌 유효한 문자열을 확인할 수 있습니다.0x 및 육형으로각의 0b이진수의 경우 0부터 시작하여 8진수로 구문 분석될 잠재적으로 더 까다로운 숫자입니다.

Ruby 1.9.2는 위의 문제를 피할 수 있도록 radix에 대한 선택적인 두 번째 인수를 추가했습니다.

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또는0X16진수입니다.0b또는0B 2진법일 입니다.0팔분일 의 이것이 할 수 .이 동작이 원하는 동작이 아닌 경우 문자열이 패턴과 일치하는지 먼저 확인하는 다른 솔루션과 조합할 수 있습니다.처럼./\d+/정규 표현 등

허용된 솔루션의 또 다른 예상치 못한 동작(1.8, 1.9는 정상):

>> Integer(:foobar)
=> 26017
>> Integer(:yikes)
=> 26025

따라서 전달되는 내용이 확실하지 않으면 다음을 추가해야 합니다..to_s.

마이런의 답변은 마음에 들지만 "나는 더 이상 자바/C# 사용하지 않기 때문에 다시는 상속을 사용하지 않을 것이다"라는 루비병을 앓고 있습니다.클래스를 여는 것은 위험할 수 있으므로 특히 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.

이진수 확인 등 초기화에 다른 모든 종류의 검사를 추가할 수 있습니다.하지만 가장 중요한 것은 루비는 사람들을 위한 것이고 사람들을 위한 것은 명확함을 의미한다는 것입니다.변수 이름과 클래스 이름을 통해 개체의 이름을 지정하면 상황이 훨씬 명확해집니다.

지난 프로젝트에서 이 문제를 해결해야 했습니다. 구현 방식은 비슷했지만 조금 달랐습니다.

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

아마도 가장 깨끗한 방법은 아니지만, 효과가 있을 것입니다.

Re: 크리스의 대답

당신의 구현은 "1a" 또는 "b2"와 같은 것들을 끝까지 다룹니다.대신에 이것은 어떻습니까?

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

다음 출력은 다음과 같습니다.

100
1a is invalid
b2 is invalid
t is invalid

언급URL : https://stackoverflow.com/questions/49274/safe-integer-parsing-in-ruby

반응형