রুবিতে নিরাপদ পূর্ণসংখ্যা পার্সিং


160

আমার একটি স্ট্রিং আছে, বলুন '123'এবং আমি এটি পূর্ণসংখ্যায় রূপান্তর করতে চাই 123

আমি জানি আপনি কেবল পারেন some_string.to_i, কিন্তু এটি রূপান্তরিত 'lolipops'হয় 0, যা আমার মনে প্রভাব নেই। আমি চাই যখন আমি একটি সুন্দর এবং বেদনাদায়ক কিছু অবৈধ রূপান্তর করার চেষ্টা করি তখন এটি আমার মুখে ফুঁকতে পারে Exception। অন্যথায়, আমি একটি বৈধ 0এবং কিছু যে শুধু একটি সংখ্যা নয় পার্থক্য করতে পারে।

সম্পাদনা: আমি রেগেক্স ট্র্যাবেরি ছাড়াই এটি করার মানক উপায়টি খুঁজছিলাম।

উত্তর:


234

রুবির এই কার্যকারিতাটি অন্তর্নির্মিত রয়েছে:

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

জোসেফ পেকোরোর উত্তরে উল্লিখিত হিসাবে আপনি বৈধ নন দশমিক সংখ্যাগুলির স্ট্রিং যেমন 0xহেক্স এবং 0bবাইনারি দ্বারা শুরু হওয়া এবং সম্ভবত শূন্য দিয়ে শুরু হওয়া আরও জটিল সংখ্যাগুলি অষ্টাল হিসাবে বিভক্ত হবে তার জন্য আপনি দেখতে চাইতে পারেন ।

রুবি ১.৯.২ র্যাডিক্সের জন্য alচ্ছিক দ্বিতীয় যুক্তি যুক্ত করেছে যাতে উপরের সমস্যাটি এড়ানো যায়:

Integer('23')                                     # => 23
Integer('0x23')                                   # => 35
Integer('023')                                    # => 19
Integer('0x23', 10)
# => #<ArgumentError: invalid value for Integer: "0x23">
Integer('023', 10)                                # => 23

27

এটি কাজ করতে পারে:

i.to_i if i.match(/^\d+$/)

8
পিএসএ: রুবিতে, ^এবং বেশিরভাগ অন্যান্য রেজিপ্যাক্স ফ্লেভারের তুলনায় মেটাচর হিসাবে মোটামুটি $ আলাদা অর্থ রয়েছে । আপনি সম্ভবত ব্যবহার \Aএবং এর \Zপরিবর্তে বলতে চাইছেন ।
pje

1
পেডেন্টিক হতে, @ পিজেএ অনুযায়ী বিভিন্ন রেজেক্স অ্যাঙ্করগুলির উল্লেখ পছন্দসই আচরণের উপর নির্ভর করে ভুল হতে পারে। পরিবর্তে ব্যবহারের বিষয়ে বিবেচনা \zস্থানে \Zযেমন মূলধন জেড নোঙ্গর বিবরণ হল: - "ম্যাচ স্ট্রিংয়ের শেষ প্রান্ত একটি newline সাথে STRING প্রান্ত, এটা ঠিক সম্পর্কে newline সামনে ম্যাচ করে।" Ruby-doc.org/core-2.1.1/Regexp .html
ডেল

24

বর্তমান গ্রহণযোগ্য সমাধানের পার্সিং হেক্স, অক্টাল এবং বাইনারি সংখ্যার উপর যে প্রভাব থাকতে পারে সে সম্পর্কেও সচেতন থাকুন:

>> Integer('0x15')
# => 21  
>> Integer('0b10')
# => 2  
>> Integer('077')
# => 63

রুবি নম্বর যে দিয়ে শুরু ইন 0xবা 0Xহেক্স হয়, 0bবা 0Bবাইনারি হয়, এবং মাত্র 0অকট্যাল হয়। যদি এটি পছন্দসই আচরণ না হয় তবে আপনি এটি সমাধান করতে পারেন এমন কয়েকটি সমাধানের সাথে যা পরীক্ষা করে দেখায় যে স্ট্রিংটি প্রথমে কোনও প্যাটার্নের সাথে মেলে কিনা check /\d+/নিয়মিত এক্সপ্রেশন ইত্যাদির মতো


1
যদিও আমি রূপান্তর থেকে এটি প্রত্যাশা করব
wvdschel

5
রুবি ১.৯-তে আপনি দ্বিতীয় আর্গুমেন্ট হিসাবে বেসটি পাস করতে পারেন।
অ্যান্ড্রু গ্রিম

17

গৃহীত সমাধানের সাথে আরেকটি অপ্রত্যাশিত আচরণ (1.8, 1.9 সহ ঠিক আছে):

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

সুতরাং আপনি যদি নিশ্চিত হন না যে কী পাস হচ্ছে তা নিশ্চিত হয়ে নিন যে আপনি একটি যুক্ত করেছেন .to_s


7
রুবি পরীক্ষায় 1.9। পূর্ণসংখ্যা (: foobar) =>
সিম্বলকে

9

আমি Myron এর উত্তর মত কিন্তু এটি রুবি রোগ ভুগছেন "আমি আর ব্যবহার জাভা / সি # তাই আমি কখনও ব্যবহার উত্তরাধিকার যাচ্ছি" । যে কোনও ক্লাস খুললে বিপদ পূর্ণ হতে পারে এবং খুব কম ব্যবহার করা উচিত, বিশেষত যখন এটি রুবির কোর লাইব্রেরির অংশ। আমি বলছি না যে এটি কখনও ব্যবহার করবেন না, তবে এটি এড়ানো সহজ easy এবং এর চেয়ে আরও ভাল বিকল্প উপলব্ধ available

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

তারপরে আপনি যখন একটি স্ট্রিং ব্যবহার করতে চান যা একটি সংখ্যা হতে পারে তখন আপনি কী করছেন তা স্পষ্ট হয়ে যায় এবং আপনি কোনও মূল বর্গ ক্লোবার না করেন eg

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.

আপনি বাইনারি সংখ্যার ইত্যাদি প্রধান বিষয় যদিও পরীক্ষা করার মত আরম্ভ অন্যান্য চেক সমস্ত প্রকারের যোগ করতে পারেন, যে রুবি মানুষের জন্য হয় এবং মানুষ মানে হচ্ছে স্বচ্ছতা । কোনও বস্তুকে এর পরিবর্তনশীল নাম এবং শ্রেণীর নাম দিয়ে নামকরণ জিনিসগুলিকে আরও পরিষ্কার করে তোলে ।


6

আমার শেষ প্রকল্পে আমাকে এটি মোকাবেলা করতে হয়েছিল, এবং আমার বাস্তবায়নও একই রকম ছিল, তবে কিছুটা আলাদা:

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

2
someString = "asdfasd123"
number = someString.to_i
if someString != number.to_s
  puts "oops, this isn't a number"
end

সম্ভবত এটি করার সবচেয়ে পরিষ্কার উপায় নয়, তবে কাজ করা উচিত।


1

উত্তর : ক্রিস এর উত্তর

আপনার বাস্তবায়নটি "1a" বা "বি 2" এর মতো জিনিসগুলি যাক। পরিবর্তে এটি সম্পর্কে কীভাবে:

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

পেডেন্টিক হতে, @ পিজেজে এবং ব্যবহৃত হিসাবে বিভিন্ন রেজেক্স অ্যাঙ্করগুলির উল্লেখ পছন্দসই আচরণের উপর নির্ভর করে ভুল হতে পারে। পরিবর্তে মূলধনী জেড অ্যাঙ্করটির বর্ণনা হিসাবে \zস্থানটির পরিবর্তে স্থানটি বিবেচনা করুন \Z: "স্ট্রিংয়ের সমাপ্তি। স্ট্রিংটি যদি নতুন লাইনের সাথে শেষ হয় তবে এটি নিউলাইনের
ডেল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.