9

In ruby I am parsing a date in the following format: 24092008. I want to convert each section (year, month, date) into a number.

I have split them up using a regex which produces three Strings which I am passing into the Integer constructor.

  date =~ /^([\d]{2})([\d]{2})([\d]{4})/
  year = Integer($3)
  month = Integer($2)
  day = Integer($1)

When it hits the month line it crashes as follows:

`Integer': invalid value for Integer: "09" (ArgumentError)

It took me a while to realise that it's interpreting the leading zero as Octal and 09 is not a valid Octal number (it works fine with "07").

Is there an elegant solution to this or should I just test for numbers less than 10 and remove the zero first?

Thanks.

prakash
  • 58,901
  • 25
  • 93
  • 115
Darren Greaves
  • 3,326
  • 4
  • 29
  • 32

4 Answers4

15

I'm not familiar with regexes, so forgive me if this answer's off-base. I've been assuming that $3, $2, and $1 are strings. Here's what I did in IRB to replicate the problem:

irb(main):003:0> Integer("04")
=> 4
irb(main):004:0> Integer("09")
ArgumentError: invalid value for Integer: "09"
    from (irb):4:in `Integer'
    from (irb):4
    from :0

But it looks like .to_i doesn't have the same issues:

irb(main):005:0> "04".to_i
=> 4
irb(main):006:0> "09".to_i
=> 9
Atiaxi
  • 1,637
  • 1
  • 13
  • 18
  • 1
    @Atiaxi: the 'invalid value' is thrown because "09" isn't a valid octal number. A leading zero typically means it is in octal, and 0-7 are the valid digits in octal. :obj.to_i converts assuming base-10. – user7116 Sep 28 '08 at 20:51
  • 1
    `String#to_i` will ignore trailing non-numeric characters. `"123abc".to_i # => 123`. This might not be desirable – Gareth Jun 29 '12 at 10:29
  • 1
    You can specify base-10 explicitly in Ruby 1.9: `Integer("09", 10) #=> 9` – Stefan Jun 20 '13 at 22:14
9

Specify base 10

Tell Ruby explicitly that you want to interpret the string as a base 10 number.

Integer("09", 10) # => 9

This is better than .to_i if you want to be strict.

"123abc".to_i # => 123
Integer("123abc", 10) # => ArgumentError

How I figured this out

In irb, method(:Integer) returns #<Method: Object(Kernel)#Integer>. That told me that Kernel owns this method, and I looked up the documentation on Kernel. The method signature shows that it takes a base as the second argument.

Nathan Long
  • 122,748
  • 97
  • 336
  • 451
1

Perhaps (0([\d])|([1-9][\d])) in place of ([\d]{2}) You may have to use $2, $4, and $5 in place of $1, $2, $3.

Or if your regexp supports (?:...) then use (?:0([\d])|([1-9][\d]))

Since ruby takes its regexp from perl, this latter version should work.

Jamie
  • 416
  • 2
  • 7
0

Instead of checking any integer with leading 0 directly. Eg:

Integer("08016") #=> ArgumentError: invalid value for Integer(): "08016"

Create a method to check and rescue for leading 0:

def is_numeric(data)
  _is_numeric = true if Integer(data) rescue false

  # To deal with Integers with leading 0
  if !_is_numeric
    _is_numeric = data.split("").all?{|q| Integer(q.to_i).to_s == q }
  end

  _is_numeric
end

is_numeric("08016") #=> true is_numeric("A8016") #=> false

Abhi
  • 4,123
  • 6
  • 45
  • 77