String > Integer Conversion Problem

Retro thanks to all who helped me with my last post. I'm certainly more
comfortable with Ruby now than then, but still a newbie as the following
will surely demonstrate.

Below, you can see that I'm checking command-line arguments to the
program for various conditions. Unfortunately, because the args are
stored as strings, when I convert them via to_i, empty and non-numerical
strings become 0. 0 is an acceptable element in this program, therefore
I can't use it to test for invalid input. I've worked around this (sort
of), by creating two sets of variables for the arguments (one set as
strings, one set as integers). Unfortunately, this complicates the
code, and more importantly, leaves me stumped concerning how to test for
non-numeric values.

So, the program does what I want, except when the args are non-numeric
strings, and the code seems uglier than it ought to be.

Thanks in advance,

-ELf

def gen_chart(max)
  x=0
  y=0
  local_chart = Array.new
  while x<=max
    y+=x
    local_chart[x]=y
    x+=1
  end
  local_chart
end

arg0 = ARGV[0]
arg1 = ARGV[1]

arg0i = ARGV[0].to_i
arg1i = ARGV[1].to_i

if arg0.nil? or (arg0i < 0) or (arg1i < 0)
  #print usage
  print <<-EOS

No args, or bad args!

Usage: #$0 [maxvalue]
       #$0 [minvalue] [maxvalue]
  EOS
elsif arg1.nil?
  #do chart to arg0, print last pair
  chart = gen_chart(arg0i)
  puts arg0i.to_s + ": " + chart[arg0i].to_s
else
  #do chart to arg1, print pairs from arg0 to last
  chart = gen_chart(arg1i)
  x=arg0i
  y=arg1i
  while x<=y
    puts x.to_s + ": " + chart[x].to_s
    x+=1
  end
end

···

--
Posted via http://www.ruby-forum.com/.

See if this gives you some ideas:

if ARGV.all? { |n| n =~ /\A\d+\Z/ }
   puts "Usage..."
   exit
else
   one, two = ARGV.map { |n| Integer(n) }
end

Hope that helps.

James Edward Gray II

···

On Dec 21, 2005, at 4:39 PM, Matthew Feadler wrote:

Below, you can see that I'm checking command-line arguments to the
program for various conditions.

Maybe this will give you an idea or two:

require 'test/unit'

def process_command_line_arguments args
  results =
  args.each do |arg|
    raise "Hey, '#{ arg }' needs to be a number" if !arg.match(/^\d*$/)
    arg = arg.to_i
    results << arg
  end
  results
end

class TestThis < Test::Unit::TestCase
  def test_command_line_processing
    assert_equal [2], process_command_line_arguments(["2"])
    assert_equal [2, 3], process_command_line_arguments(["2", "3"])
    assert_raise(RuntimeError) { process_command_line_arguments(["-1"]) }
    assert_raise(RuntimeError) { process_command_line_arguments(["1", "oog"]) }
    assert_raise(RuntimeError) { process_command_line_arguments(["boo", "oog"])}
  end
end

$ ruby a.rb
Loaded suite a
Started
.
Finished in 0.001163 seconds.

1 tests, 5 assertions, 0 failures, 0 errors

···

On 12/21/05, Matthew Feadler <matthew@feadler.com> wrote:

Retro thanks to all who helped me with my last post. I'm certainly more
comfortable with Ruby now than then, but still a newbie as the following
will surely demonstrate.

Below, you can see that I'm checking command-line arguments to the
program for various conditions. Unfortunately, because the args are
stored as strings, when I convert them via to_i, empty and non-numerical
strings become 0. 0 is an acceptable element in this program, therefore
I can't use it to test for invalid input. I've worked around this (sort
of), by creating two sets of variables for the arguments (one set as
strings, one set as integers). Unfortunately, this complicates the
code, and more importantly, leaves me stumped concerning how to test for
non-numeric values.

So, the program does what I want, except when the args are non-numeric
strings, and the code seems uglier than it ought to be.

Thanks in advance,

-ELf

def gen_chart(max)
  x=0
  y=0
  local_chart = Array.new
  while x<=max
    y+=x
    local_chart=y
    x+=1
  end
  local_chart
end

arg0 = ARGV[0]
arg1 = ARGV[1]

arg0i = ARGV[0].to_i
arg1i = ARGV[1].to_i

if arg0.nil? or (arg0i < 0) or (arg1i < 0)
  #print usage
  print <<-EOS

No args, or bad args!

Usage: #$0 [maxvalue]
       #$0 [minvalue] [maxvalue]
  EOS
elsif arg1.nil?
  #do chart to arg0, print last pair
  chart = gen_chart(arg0i)
  puts arg0i.to_s + ": " + chart[arg0i].to_s
else
  #do chart to arg1, print pairs from arg0 to last
  chart = gen_chart(arg1i)
  x=arg0i
  y=arg1i
  while x<=y
    puts x.to_s + ": " + chart.to_s
    x+=1
  end
end

Matthew Feadler wrote:

Retro thanks to all who helped me with my last post. I'm certainly more comfortable with Ruby now than then, but still a newbie as the following will surely demonstrate.

Below, you can see that I'm checking command-line arguments to the program for various conditions. Unfortunately, because the args are stored as strings, when I convert them via to_i, empty and non-numerical strings become 0. 0 is an acceptable element in this program, therefore I can't use it to test for invalid input. I've worked around this (sort of), by creating two sets of variables for the arguments (one set as strings, one set as integers). Unfortunately, this complicates the code, and more importantly, leaves me stumped concerning how to test for non-numeric values.

The Integer() method raises ArgumentError if given an empty, non-numeric, or otherwise non-well-formed string.

Hi --

···

On Thu, 22 Dec 2005, Matthew Feadler wrote:

Retro thanks to all who helped me with my last post. I'm certainly more
comfortable with Ruby now than then, but still a newbie as the following
will surely demonstrate.

Below, you can see that I'm checking command-line arguments to the
program for various conditions. Unfortunately, because the args are
stored as strings, when I convert them via to_i, empty and non-numerical
strings become 0. 0 is an acceptable element in this program, therefore
I can't use it to test for invalid input. I've worked around this (sort
of), by creating two sets of variables for the arguments (one set as
strings, one set as integers). Unfortunately, this complicates the
code, and more importantly, leaves me stumped concerning how to test for
non-numeric values.

So, the program does what I want, except when the args are non-numeric
strings, and the code seems uglier than it ought to be.

In addition to the other suggestions, you might find scanf useful:

   require 'scanf'
   arg0, arg1 = ARGV.join.scanf("%d%d")

or something like that.

David

--
David A. Black
dblack@wobblini.net

"Ruby for Rails", from Manning Publications, coming April 2006!

What about something like

{|x| x == x.to_i.to_s}

If the string the above block is applied to is not a number, this
should fail, right?

-Rich

···

On 12/21/05, Matthew Feadler <matthew@feadler.com> wrote:

Retro thanks to all who helped me with my last post. I'm certainly more
comfortable with Ruby now than then, but still a newbie as the following
will surely demonstrate.

Below, you can see that I'm checking command-line arguments to the
program for various conditions. Unfortunately, because the args are
stored as strings, when I convert them via to_i, empty and non-numerical
strings become 0. 0 is an acceptable element in this program, therefore
I can't use it to test for invalid input. I've worked around this (sort
of), by creating two sets of variables for the arguments (one set as
strings, one set as integers). Unfortunately, this complicates the
code, and more importantly, leaves me stumped concerning how to test for
non-numeric values.

So, the program does what I want, except when the args are non-numeric
strings, and the code seems uglier than it ought to be.

Thanks in advance,

-ELf

def gen_chart(max)
  x=0
  y=0
  local_chart = Array.new
  while x<=max
    y+=x
    local_chart=y
    x+=1
  end
  local_chart
end

arg0 = ARGV[0]
arg1 = ARGV[1]

arg0i = ARGV[0].to_i
arg1i = ARGV[1].to_i

if arg0.nil? or (arg0i < 0) or (arg1i < 0)
  #print usage
  print <<-EOS

No args, or bad args!

Usage: #$0 [maxvalue]
       #$0 [minvalue] [maxvalue]
  EOS
elsif arg1.nil?
  #do chart to arg0, print last pair
  chart = gen_chart(arg0i)
  puts arg0i.to_s + ": " + chart[arg0i].to_s
else
  #do chart to arg1, print pairs from arg0 to last
  chart = gen_chart(arg1i)
  x=arg0i
  y=arg1i
  while x<=y
    puts x.to_s + ": " + chart.to_s
    x+=1
  end
end

--
Posted via http://www.ruby-forum.com/\.

Whoops, this is probably better:

def process_command_line_arguments args
  args.map do |arg|
    raise "Hey, '#{ arg }' needs to be a number" if !arg.match(/^\d*$/)
    arg.to_i
  end
end

Passes all the tests.

···

On 12/21/05, Joe Van Dyk <joevandyk@gmail.com> wrote:

On 12/21/05, Matthew Feadler <matthew@feadler.com> wrote:
> Retro thanks to all who helped me with my last post. I'm certainly more
> comfortable with Ruby now than then, but still a newbie as the following
> will surely demonstrate.
>
> Below, you can see that I'm checking command-line arguments to the
> program for various conditions. Unfortunately, because the args are
> stored as strings, when I convert them via to_i, empty and non-numerical
> strings become 0. 0 is an acceptable element in this program, therefore
> I can't use it to test for invalid input. I've worked around this (sort
> of), by creating two sets of variables for the arguments (one set as
> strings, one set as integers). Unfortunately, this complicates the
> code, and more importantly, leaves me stumped concerning how to test for
> non-numeric values.
>
> So, the program does what I want, except when the args are non-numeric
> strings, and the code seems uglier than it ought to be.
>
> Thanks in advance,
>
> -ELf
>
> def gen_chart(max)
> x=0
> y=0
> local_chart = Array.new
> while x<=max
> y+=x
> local_chart=y
> x+=1
> end
> local_chart
> end
>
> arg0 = ARGV[0]
> arg1 = ARGV[1]
>
> arg0i = ARGV[0].to_i
> arg1i = ARGV[1].to_i
>
> if arg0.nil? or (arg0i < 0) or (arg1i < 0)
> #print usage
> print <<-EOS
>
> No args, or bad args!
>
> Usage: #$0 [maxvalue]
> #$0 [minvalue] [maxvalue]
> EOS
> elsif arg1.nil?
> #do chart to arg0, print last pair
> chart = gen_chart(arg0i)
> puts arg0i.to_s + ": " + chart[arg0i].to_s
> else
> #do chart to arg1, print pairs from arg0 to last
> chart = gen_chart(arg1i)
> x=arg0i
> y=arg1i
> while x<=y
> puts x.to_s + ": " + chart.to_s
> x+=1
> end
> end

Maybe this will give you an idea or two:

require 'test/unit'

def process_command_line_arguments args
  results =
  args.each do |arg|
    raise "Hey, '#{ arg }' needs to be a number" if !arg.match(/^\d*$/)
    arg = arg.to_i
    results << arg
  end
  results
end

class TestThis < Test::Unit::TestCase
  def test_command_line_processing
    assert_equal [2], process_command_line_arguments(["2"])
    assert_equal [2, 3], process_command_line_arguments(["2", "3"])
    assert_raise(RuntimeError) { process_command_line_arguments(["-1"]) }
    assert_raise(RuntimeError) { process_command_line_arguments(["1", "oog"]) }
    assert_raise(RuntimeError) { process_command_line_arguments(["boo", "oog"])}
  end
end

$ ruby a.rb
Loaded suite a
Started
.
Finished in 0.001163 seconds.

1 tests, 5 assertions, 0 failures, 0 errors

Neat, didn't know about Enumerable#all? or about Integer().

···

On 12/21/05, James Edward Gray II <james@grayproductions.net> wrote:

On Dec 21, 2005, at 4:39 PM, Matthew Feadler wrote:

> Below, you can see that I'm checking command-line arguments to the
> program for various conditions.

See if this gives you some ideas:

if ARGV.all? { |n| n =~ /\A\d+\Z/ }
   puts "Usage..."
   exit
else
   one, two = ARGV.map { |n| Integer(n) }
end

So could we rewrite this as:

begin
  one, two = ARGV.map{ |n| Integer(n) }
rescue ArgumentError
  puts Usage
  exit
end

?

Jacob Fugal

···

On 12/21/05, Timothy Hunter <cyclists@nc.rr.com> wrote:

The Integer() method raises ArgumentError if given an empty,
non-numeric, or otherwise non-well-formed string.

On 12/21/05, James Edward Gray II <james@grayproductions.net> wrote:

if ARGV.all? { |n| n =~ /\A\d+\Z/ }
   puts "Usage..."
   exit
else
   one, two = ARGV.map { |n| Integer(n) }
end

Me too. I'm definitely getting tunnel vision on the core doc, and ignoring the standard library a bit. Thanks for another good lead :slight_smile:

···

On Thu, 22 Dec 2005 00:21:39 -0000, <dblack@wobblini.net> wrote:

In addition to the other suggestions, you might find scanf useful:

--
Ross Bamford - rosco@roscopeco.remove.co.uk

Rich wrote:

What about something like

{|x| x == x.to_i.to_s}

If the string the above block is applied to is not a number, this
should fail, right?

It will fail for "012" as well.

Jacob Fugal wrote:

begin
  one, two = ARGV.map{ |n| Integer(n) }
rescue ArgumentError
  puts Usage
  exit
end

When the arguments to Integer are strings from the command line, yes. In the general case Integer() can raise TypeError as well as ArgumentError, for arguments like Integer([1,2])

Yeah, that's better. Neither of our versions checks the number of arguments though and we probably should...

James Edward Gray II

···

On Dec 21, 2005, at 6:13 PM, Jacob Fugal wrote:

On 12/21/05, Timothy Hunter <cyclists@nc.rr.com> wrote:

The Integer() method raises ArgumentError if given an empty,
non-numeric, or otherwise non-well-formed string.

On 12/21/05, James Edward Gray II <james@grayproductions.net> wrote:

if ARGV.all? { |n| n =~ /\A\d+\Z/ }
   puts "Usage..."
   exit
else
   one, two = ARGV.map { |n| Integer(n) }
end

So could we rewrite this as:

begin
  one, two = ARGV.map{ |n| Integer(n) }
rescue ArgumentError
  puts Usage
  exit
end

I see really two things happening here, string->int conversions and
command line parsing. Once you have the conversions understood (a good
thing to know) consider exploring more stuff in the packages.

Let me point you to OptionParser and GetOptLong. They both provide some
very useful command line parsing capabilities. It takes a little
experimentation to really understand what's happening but well worth it
in my opinion.

-dwh-

True, but I *was* referring specifically to the command line; vis the
OP's question, and evidenced by my use of ARGV. :slight_smile:

Jacob Fugal

···

On 12/21/05, Timothy Hunter <cyclists@nc.rr.com> wrote:

Jacob Fugal wrote:
> begin
> one, two = ARGV.map{ |n| Integer(n) }
> rescue ArgumentError
> puts Usage
> exit
> end

When the arguments to Integer are strings from the command line, yes. In
the general case Integer() can raise TypeError as well as ArgumentError,
for arguments like Integer([1,2])

Excuse my ruby "newb-ness", but what does this line actually do? Mainly, what's throwing me off is the "one, two" assignment (or whatever it is).

···

On Dec 21, 2005, at 11:20 PM, James Edward Gray II wrote:

  one, two = ARGV.map{ |n| Integer(n) }

I'm just wondering, in Java it's a bit of a no-no using exceptions like this (since they're pretty heavy to put together). Is it the case in Ruby? And does that regexp match balance it out anyway?

···

On Thu, 22 Dec 2005 04:20:04 -0000, James Edward Gray II <james@grayproductions.net> wrote:

On Dec 21, 2005, at 6:13 PM, Jacob Fugal wrote:

On 12/21/05, Timothy Hunter <cyclists@nc.rr.com> wrote:

The Integer() method raises ArgumentError if given an empty,
non-numeric, or otherwise non-well-formed string.

On 12/21/05, James Edward Gray II <james@grayproductions.net> wrote:

if ARGV.all? { |n| n =~ /\A\d+\Z/ }
   puts "Usage..."
   exit
else
   one, two = ARGV.map { |n| Integer(n) }
end

So could we rewrite this as:

begin
  one, two = ARGV.map{ |n| Integer(n) }
rescue ArgumentError
  puts Usage
  exit
end

Yeah, that's better. Neither of our versions checks the number of arguments though and we probably should...

--
Ross Bamford - rosco@roscopeco.remove.co.uk

Try:

irb(main):001:0> one, two = 3, 4
=> [3, 4]
irb(main):002:0> one
=> 3
irb(main):003:0> two
=> 4

It's a multiple assignment. It takes multiple values (or an array) and spits
them into what's on the left.

Map simply iterates through an array and runs the block (the thing in braces)
each item, storing the result.

Thus, we're converting everything in the ARGV array to an integer and stuffing
it into two variables. The reason everyone else was saying it would be a
good idea to check the length is the following:

irb(main):004:0> one, two = 3, 4, 5
=> [3, 4, 5]
irb(main):005:0> one
=> 3
irb(main):006:0> two
=> 4

Kinda bad to have mysteriously disappearing command line arguments. :slight_smile: Play
around with it and I'm sure you'll get the hang of it. Oh, and welcome to
Ruby! :smiley:

···

On Wednesday 21 December 2005 22:26, J. Ryan Sobol wrote:

On Dec 21, 2005, at 11:20 PM, James Edward Gray II wrote:
>> one, two = ARGV.map{ |n| Integer(n) }

Excuse my ruby "newb-ness", but what does this line actually do?
Mainly, what's throwing me off is the "one, two" assignment (or
whatever it is).

I disagree that this particular use of an exception would be a no-no in
Java. Inability to parse input is justifiably an "exceptional" case.
And the handling of that exceptional case is also appropriate.

The big "no-no" about exception usage is true for any language: "Don't
use exceptions for flow control".

The following code is "wrong" for various reasons as well as violating
the "axiom" above:

begin
  # display 1 through 10
  i = 0
  while true
    unless i > 10
      puts i
    else
      raise "End o' the line"
    end
    i += 1
  end
rescue
end

Ruby provides enough mechanisms for "controlling the flow" that using
exceptions for "normal" conditions is definitely poor style, if not
worse.

BTW "continuations" (related to exceptions) are a fairly powerful tool
to handle the times when strange flow control might be needed.

I disagree that this particular use of an exception would be a no-no in
Java. Inability to parse input is justifiably an "exceptional" case.
And the handling of that exceptional case is also appropriate.

Agreed, I was referring more to the idea of swapping out flow control for exceptions in general. Obviously if the input is an exceptional case, throw an exception. I have just been wondering about a few examples of this I've seen in Ruby code, and just picked this as an 'in' to ask about it :wink:

The big "no-no" about exception usage is true for any language: "Don't
use exceptions for flow control".

The following code is "wrong" for various reasons as well as violating
the "axiom" above:

begin
  # display 1 through 10
  i = 0
  while true
    unless i > 10
      puts i
    else
      raise "End o' the line"
    end
    i += 1
  end
rescue
end

Ruby provides enough mechanisms for "controlling the flow" that using
exceptions for "normal" conditions is definitely poor style, if not
worse.

Okay, good. That was my feeling too.

BTW "continuations" (related to exceptions) are a fairly powerful tool
to handle the times when strange flow control might be needed.

I can't wait to find something I can try continuations out on, though I remember reading somewhere that they too are slow, so one to keep for those strange cases as you say?

Cheers,

···

On Thu, 22 Dec 2005 14:07:03 -0000, jwesley <justin.w.smith@gmail.com> wrote:

--
Ross Bamford - rosco@roscopeco.remove.co.uk