G Nagasri Varma has asked for the wisdom of the Perl Monks concerning the following question:

Program :

#!/usr/bin/perl use warnings; print "Enter no of days older : \n"; $days = <STDIN>; chomp $days; if ($days = ~ /^\s*[1-9][0-9]*\s*$/) { print "Inside if : $days \n\n"; } else { print "Inside else \n\n"; }
o/p :

Enter no of days older :
9
Use of uninitialized value in pattern match (m//) at ./tt.pl line 8, < +STDIN> line 1.
Inside if : 18446744073709551615

I dont want my $days value to change after Inside if statement. And how can the warning of uninitialized value be reolved?
And is the regex apt for validating whether the entered input is a positive integer or not and also greater than zero?

Replies are listed 'Best First'.
Re: Validation of UserInput is a positive Integer or not?
by ww (Archbishop) on Dec 07, 2015 at 19:17 UTC

    Short answer: NO, not even close!

    Longer answer:

    #!/usr/bin/perl use strict; use warnings; # 1149595 print "Enter number of days (1..90, no fractions or negative values): +"; my $days = <STDIN>; chomp $days; # if ($days =~ /^\s*1-90-9*\s*$/) { # the numeric "test" is hopeless +ly wrong # the "^\s* allows user to enter leading spaces # regex permits a trailing space to match despite +the chomp # ....BUT, a regex is probably the wrong way to go +... #if (0 < $days && $days <= 90 && $days =~ /^\d\d$/ ) { # makes the + exact test explicit if ( (0 < $days) && ($days <= 90) && ($days =~ /^\d\d$/) ) { # some m +ay prefer this print "Inside if, satisfied the spec: $days \n\n"; } else { print "Days entered do not meet spec: $days \n\n"; # tell the use +r specificly }

    Update Added missing "use strict;" --- aaaerg! (and fixed misallignment of some comments).


    check Ln42!

      I'd suggest a couple minor changes to update this line in your original version:

      if ( (0 < $days) && ($days <= 90) && ($days =~ /^\d\d$/) )
      with this one:
      if ( ($days =~ /^\d+$/) && (0 < $days) && ($days <= 90) )

      This avoids printing a warning of Argument "x" isn't numeric in numeric lt (<) by doing the regex test first (consider what the code does with an alpha-string.) Further, the original regex disallows values like "1" which are within the desired spec. No real harm in allowing any number of digits since the later tests verify the range, although using a repeat of {1,2} could also work (I personally try to avoid it as it makes updating the range in the future more complex.)

        Apero offers a valid and valuable learning point in suggesting that the order of the tests be changed.

        But (in an exchange via CB) Apero cites the possibility that an idiot responding to a prompt asking for integers between 0 and 91 with "hi" will cause perl to "spew warnings." I disagree with the view that this is a bad thing in this case.

        In fact, the issuance of warnings might (well, not likely, but "might") cause my not-entirely-hypothetical idiot to actually read the prompt, once that's written in a manner which makes the required input explicit.

        And, while I'm (politely, I trust) disagreeing with fellow Monks, the notion of adding a prompt module from BillKSmith is also, IMO, a valid teaching point, but an unnecessary addition to overhead, because OP's intent (as stated in the narrative) is simply validation of an input. Further, since OP's code - were it corrected as ExReg suggests or as modified in my note - does the same job, inline and very clearly for any future reader or maintainer.

        Fixed: missing char and extra close tag

Re: Validation of UserInput is a positive Integer or not?
by toolic (Bishop) on Dec 07, 2015 at 17:22 UTC
Re: Validation of UserInput is a positive Integer or not?
by BillKSmith (Monsignor) on Dec 07, 2015 at 21:51 UTC
    If you must validate user input, it is worth using a prompt module. It not only detects the errors, it gives the user a chance to correct them.
    #!/usr/bin/perl use strict; use warnings; use IO::Prompt::Hooked; my $days = prompt( message => "Enter no of days older (1-90):", error => "Invalid input, please try again\n", validate => sub { my $days = shift; return ( $days =~ /^[1-9]\d?$/ and $days <= 90 ); }, ); print "You entered $days days\n\n";

    The following sample run shows the recovery from several errors.

    :tt.pl Enter no of days older (1-90): a Invalid input, please try again Enter no of days older (1-90): ! Invalid input, please try again Enter no of days older (1-90): 333 Invalid input, please try again Enter no of days older (1-90): 99 Invalid input, please try again Enter no of days older (1-90): 07 Invalid input, please try again Enter no of days older (1-90): 9 You entered 9 days :
    Bill
Re: Validation of UserInput is a positive Integer or not?
by karlgoethebier (Abbot) on Dec 07, 2015 at 20:57 UTC
    "...Input is a positive Integer or not"

    Try this:

    #!/usr/bin/env perl use strict; use warnings; use Inline Java => q(./Karl.java); use feature qw(say); say Karl->isaInt($_) for ( -10, 0, 10 ); __END__ karls-mac-mini:inline karl$ ./run.pl -1 0 1

    Karl.java:

    import java.lang.Integer; class Karl { private Karl(){ } public static int isaInt( int n){ return Integer.signum(n); } }

    It seems like it works ;-)

    I guess that they burn me for this.

    Please see also Inline.

    Regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

      Moose has type validation but I have never tried to use it stand alone. I did find the Data::Types module useful.

      #!/usr/bin/perl use warnings; use strict; use Data::Types qw(is_int); foreach ( qw( 1.1 -2 0 3 hi 0.0 2e5 0b11 ), 0b11 ){ print $_, (is_int($_) and $_>0) ? ' is':' is not', " a positive in +teger.\n"; } __DATA__ 1.1 is not a positive integer. -2 is not a positive integer. 0 is not a positive integer. 3 is a positive integer. hi is not a positive integer. 0.0 is not a positive integer. 2e5 is not a positive integer. 0b11 is not a positive integer. 3 is a positive integer.

        Cool. Yet another module i didn't know.

        Thanks and best regards, Karl

        «The Crux of the Biscuit is the Apostrophe»

Re: Validation of UserInput is a positive Integer or not?
by ExReg (Priest) on Dec 07, 2015 at 20:05 UTC

    I think what you meant to write was

    if ($days =~ /^\s*[1-9][0-9]*\s*$/)

    The way you wrote it, it would only match a value of $days equal to "1-90-9" plus or minus leading/trailing spaces and the last nine.

    Much better is the approach taken by toolic, ww, and Apero.