programmercarlito has asked for the wisdom of the Perl Monks concerning the following question:

Wondering how to get just numbers.So far it seems to work for the first two paragraphs of code but when it gets to the third piece it just doesnt seem to work.The if and else statement dont work. Dont worry about the last 3. I havent modified those to my liking yet. Thanks

print"Enter the starting amount: "; $startAmount = <stdin>; while($startAmount == ""){ print"Numbers only! Try again: "; $startAmount = <stdin>; };chomp($startAmount); print"Enter your current age: "; $startAge = <stdin>; while($startAge == ""){ print"Numbers only! Try again: "; $startAge = <stdin>; };chomp($startAge); print"Enter the age you want to retire: "; $endAge = <stdin>; while($endAge == ""){ if($endAge >= $startAge){ print"Age you want to retire must be greater than current age\n"; $endAge = <stdin>; }#ends if else{ print"Numbers only! Try again: "; $endAge = <stdin>; }#ends else };chomp($endAge); print "Enter amount deposited per year: "; $yearlyDeposit = <stdin>; chomp($yearlyDeposit); print "Enter the Annual interest rate: "; $annualInterest = <stdin>; chomp($annualInterest); print "Enter Expected Retirement Money: "; $expectedMoney = <stdin>; chomp($expectedMoney); system("pause");

Replies are listed 'Best First'.
Re: Stdin for just numbers
by Athanasius (Archbishop) on Mar 16, 2015 at 01:13 UTC

    Hello programmercarlito,

    Actually, the first two paragraphs are not working correctly as you believe. There are three problems. First, after $startAmount = <stdin> the variable $startAmount always ends in a newline character (or character sequence), so it is never the empty string. You need to chomp it before you test it.

    Second, == compares numbers, but "" is a string. You should use eq instead: while($startAmount eq ""){.

    Third, testing for an empty string won’t tell you whether the user has input a valid number. See How-do-I-determine-whether-a-scalar-is-a-number-whole-integer-float of perlfaq4.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Stdin for just numbers.
by graff (Chancellor) on Mar 16, 2015 at 02:01 UTC
    If you really want to go with this sort of "extended dialog" via stdin, you should check out Term::ReadLine.

    Here's one way to structure things so that the coding is easier. (I'm just going with basic usage in this example - the module has various options and extra methods to make things easier for the person who is typing, such as keeping a history of responses, so they can be recalled and reused, etc. Notice that Term::ReadLine strips off the newline characters for you.)

    #!/usr/bin/perl use strict; use warnings; use Term::ReadLine; my $term = Term::ReadLine->new(); my @prompts = ( "the starting amount", "your current age", "the age you want to retire", "amount deposited per year", "the annual interest rate", "expected retirement money" ); my %responses; for my $prompt ( @prompts ) { my $response = ''; until ( $response =~ /^\d+$/ ) { $response = $term->readline( "Enter $prompt: " ); last unless defined( $response ); if ( $response =~ /\D/ ) { warn "Numeric answers only, please. Try again.\n"; } elsif ( $prompt eq "the age you want to retire" and $response < $responses{"your current age"} ) { warn sprintf( "We can't change the past. Give me a number +> %d\n", $responses{"your current age"} ); $response = ""; } } $responses{$prompt} = $response if ( defined( $response )); } printf "\nThank you for your %d answers\n", scalar keys( %responses ); for ( @prompts ) { print " $_ : $responses{$_}\n" if ( exists( $responses{$_} )); }
    (There are different "flavors" of Term::ReadLine that you can use; your perl version probably has a "default" version that will suit your needs.)
      A module is definitely the way to go. I would prefer IO::Prompt::Hooked. It works on all operating systems and provides validation and retry.
      Bill

        You could also use IO::Prompter, which I only recently learned about.

        #!/usr/bin/perl use strict; use warnings; use feature qw/say/; use IO::Prompter; my %responses = (); my @prompts = ( ["startamount", "the starting amount", ""], ["startage", "your current age", ""], ["endage", "the age you want to retire", sub { $_ >= $r +esponses{'startage'} } ], ["yearlydeposit", "amount deposited per year", ""], ["annualinterest", "the Annual interest rate", ""], ["expectedmoney", "Expected Retirement Money", ""], ); foreach my $prompt (@prompts) { $responses{$prompt->[0]} = prompt "Enter $prompt->[1]:", -num => $ +prompt->[2] } foreach (sort keys %responses) { say "$_: $responses{$_}"; }

        There's probably a better way of specifying empty constraints -- though the OP will likely some constraints that goes beyond "it's a number" imposed on most of the input.

        ++ for recommending my module (IO::Prompt::Hooked). I actually implemeneted a solution to the OP's question using IO::Prompt::Hooked last night, and it looked (in my opinion) great. ...but it became late, and I was too tired to submit a post around it. :)

        Anyway, this is exactly the sort of thing that IO::Prompt::Hooked aims to simplify.


        Dave

Re: Stdin for just numbers.
by LanX (Saint) on Mar 16, 2015 at 01:03 UTC
Re: Stdin for just numbers.
by shmem (Chancellor) on Mar 16, 2015 at 14:48 UTC

    If you want only numbers, you have to check for numbers. One way to do that:

    print"Enter the starting amount: "; while( $startAmount !~ /^\d+/ ) { $startAmount = <STDIN>; chomp( $startAmount ); if ( $startAmount !~ /^\d+$/ ) { print"Numbers only! Try again: "; } else { last; } }

    The above checks $startAmount twice. We can avoid that with a bare block and redo:

    print"Enter the starting amount: "; { chomp( $startAmount = <STDIN> ); unless ( $startAmount =~ /^\d+$/ ) { print"Numbers only! Try again: "; redo; } # this line is reached if $startAmount is a number print "ok, \$startAmount is $startAmount\n"; }

    There are many more ways to do that...

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: Stdin for just numbers. (use Getopt::Long)
by jeffa (Bishop) on Mar 16, 2015 at 16:53 UTC

    I don't recommend writing applications that interact with a user, asking the user to enter data. Such applications may seem beneficial to the end user, but not if that end user is another application. Rather, use tools that provide a means to accomplish both readability (for humans) and non-inter-activeness (for non-humans). In other words, consider using command line arguments over reading in "raw" STDIN.

    #!/usr/bin/env perl use strict; use warnings; use Data::Dumper; use Getopt::Long; use Pod::Usage; my @opts = qw( starting-amount current-age retire-age deposit interest expected ); GetOptions ( ( \my %args => map "$_=i", @opts ), 'help' => \my $help, 'man' => \my $man, ); pod2usage( -verbose => 1 ) if $help; pod2usage( -verbose => 2 ) if $man; for (@opts) { pod2usage( -msg => "$_ is required", -exitval => -1, -verbose => 0, ) unless defined $args{$_}; } pod2usage( -msg => "retire-age must be greater than current-age", -exitval => -1, -verbose => 0, ) if $args{'retire-age'} <= $args{'current-age'}; print Dumper \%args; __END__ =head1 NAME retirement-calculator - app to calculate retirement amount =head1 SYNOPSIS retirement-calculator [options] Options: --starting-amount the amount to start retirement with --current-age how old you currently are --retire-age what age you want to retire at --deposit amount deposited per year --interest annual interest rate --expected what you expect to retire with --help list usage --man print man page =cut

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)