آمنة صحيح تحليل في روبي
-
09-06-2019 - |
سؤال
لدي سلسلة ، يقول '123'
, و أريد تحويله إلى 123
.
وأنا أعلم أنك يمكن أن تفعل ببساطة some_string.to_i
, لكن الذي يحول 'lolipops'
إلى 0
, التي ليس لها تأثير علي في الاعتبار.أريد أن ينفجر في وجهي عندما كنت في محاولة لتحويل شيء صالح ، مع لطيفة و مؤلمة Exception
.وإلا لا أستطيع التمييز بين صالح 0
و شيء فقط لا عدد على الإطلاق.
تحرير: كنت أبحث عن طريقة قياسية من يفعل ذلك ، دون regex الخداع.
المحلول
روبي كانت هذه الوظيفة بنيت في:
Integer('1001') # => 1001
Integer('1001 nights')
# ArgumentError: invalid value for Integer: "1001 nights"
كما ذكر في الجواب من قبل جوزيف بيكورارو, قد ترغب في مشاهدة سلاسل صالحة غير الأرقام العشرية ، مثل تلك التي بدأت مع 0x
عرافة ، 0b
الثنائية ، ويحتمل أن تكون أكثر صعبة أرقام بدءا من الصفر التي سيتم تحليلها كما الثماني.
روبي 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+$/)
أيضا أن تكون على بينة من يؤثر أن التيار تقبل الحل قد يكون على تحليل عرافة الثماني ، و الأرقام الثنائية:
>> Integer('0x15')
# => 21
>> Integer('0b10')
# => 2
>> Integer('077')
# => 63
في روبي الأرقام التي تبدأ مع 0x
أو 0X
هي عرافة ، 0b
أو 0B
هي الثنائية فقط 0
هي ثماني.إذا كان هذا ليس هو السلوك المطلوب قد ترغب في الجمع بين ذلك مع بعض الحلول الأخرى التي تحقق مما إذا كانت سلسلة مباريات النمط الأول.مثل /\d+/
التعبيرات العادية ، إلخ.
آخر سلوك غير متوقع مع الحل المقبول (مع 1.8 و 1.9 هو موافق):
>> Integer(:foobar)
=> 26017
>> Integer(:yikes)
=> 26025
حتى إذا كنت غير متأكد من ما يجري تمريرها في, تأكد من إضافة .to_s
.
أنا أحب مايرون الإجابة لكنها تعاني من روبي مرض "أنا لم يعد استخدام Java/C# حتى أنا لن تستخدم الميراث مرة أخرى".فتح أي فئة يمكن أن تكون محفوفة بالمخاطر و يجب أن تستخدم لماما ، خاصة عندما يكون جزء من روبي مكتبة الأساسية.أنا لا أقول لا تستخدم أي وقت مضى ، ولكن عادة ما يكون من السهل تجنب وأن هناك أفضل الخيارات المتاحة ، مثل
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