http://qs321.pair.com?node_id=614452

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

Just a note I have seen hundreds of forums and this one is the best above the best. Always get quick answers with no attitudes and always get the help from the best people who really enjoy helping people. Is there a place to donate or help fund this great site??

My Perl question is I need to create a regular expression in Perl to find if anything except a positive integer was entered.

No letters or characters except a positive integer. For example the regular expression will check
12 good entry.
1a bad entry
4 good entry
1a bad entry
-3 bad entry
test bad entry

My attempt is not validating like I want it to:
if($DataEntry =~ !/d.*+) { print "bad entry"; } else { print "good entry"; }
Please advise.

Replies are listed 'Best First'.
Re: Check for Positive Integer entry only
by kyle (Abbot) on May 09, 2007 at 17:33 UTC

    You might want to look at Regexp::Common::number in general, but I don't see anything ready-made to do what you want. Here's a pattern I might use:

    $dataEntry =~ m{ \A # beginning of string \+? # optional plus sign \d+ # one or more digits \z # end of string }xms

    Using Regexp::Common, that might be:

    use Regexp::Common qw( number ); $dataEntry =~ /$RE{num}{int}/ && $dataEntry == abs $dataEntry

    If you want to allow for white space in your data entry, you could add \s* into your patterns.

    Update: After consideration of the contributions of the other monks, I think this is a better expression than the one I have above:

    m{ \A # beginning of string \+? # optional plus sign [0-9]* # optional digits, including zero [1-9] # mandatory non-zero digit [0-9]* # optional digits, including zero \z # end of string }xms

    This incorporates Nkuvu's observation that a value of zero should not be allowed and mreece's suggestion that \d is not always the best way to match digits (though I find this counterintuitive). It also passes my own test suite.

Re: Check for Positive Integer entry only
by friedo (Prior) on May 09, 2007 at 17:16 UTC
    This should do it:
    if ( $DataEntry =~ /^\d+$/ ) { print "good entry"; } else { print "bad entry"; }

      Add in a test for zero -- that passes through this regex, but is not a positive integer by any definition I'm aware of.

      That also passes for "123\n" which could be good or bad. Use \z instead of $ if you don't want to allow a trailing \n.
Re: Check for Positive Integer entry only
by jasonk (Parson) on May 09, 2007 at 17:15 UTC

    While !/d.*+ vaguely resembles a regular expression, I suspect you want to read perlre, because what you have there is not a regular expression (or perl for that matter, since it won't even compile.)


    We're not surrounded, we're in a target-rich environment!
Re: Check for Positive Integer entry only
by swampyankee (Parson) on May 09, 2007 at 18:08 UTC

    I think that this exact case is handled in the Camel Book.

    The logic is quite straightforward:

    #!perl use strict; use warnings; while (<DATA>) { chomp; # get rid of pesky newlines if(is_integer_string($_)){ print "$_ is a valid integer string\n"; } else { print "$_ isn't a valid integer string\n"; } } sub is_integer_string { # a valid integer is any amount of white space, followed # by an optional sign, followed by at least one digit, # followed by any amount of white space return $_[0] =~ /^\s*[\+\-]?\d+\s*$/; } __DATA__ 1 1234 +1234 -1234 A 1234+ + 1234

    Note that this does not check to see if the integer can be represented on your system. It also does not permit white space between the sign and the leading digit of the number being examined.


    Oops! This will pass 0, which is not a positive integer, although it is a valid integer.

    To correct the test replace this:
    return $_[0] =~ /^\s*[\+\-]?\d+\s*$/;
    with this
    if(( $_[0] =~ /^\s*[\+\-]?\d+\s*$/) and ($_[0] > 0)) { return 1; } else{ return undef; }

    Doubtless, this is not the most efficient method.

    emc

    Insisting on perfect safety is for people who don't have the balls to live in the real world.

    —Mary Shafer, NASA Dryden Flight Research Center
Re: Check for Positive Integer entry only
by Nkuvu (Priest) on May 09, 2007 at 17:44 UTC

    Is there a place to donate or help fund this great site??

    See the Offering Plate for contribution details.

Re: Check for Positive Integer entry only
by mreece (Friar) on May 09, 2007 at 21:59 UTC
    i'm not a big fan of \d, since it can lead to unexpected results: matching things that are "digits" but not useable as perl or database integers. when unicode enters the picture, there are 268 or so unicode characters that \d matches against.

    what you probably want here is a string that starts with a number 1-9, followed by more numbers 0-9 (assuming that 03 is a bad entry), or just one or more numbers 0-9 (if 03 is a good entry).

    if ($DataEntry =~ /^[1-9][0-9]*$/) { print "good entry\n"; } else { print "bad entry\n"; }
    or
    if ($DataEntry =~ /^[0-9]+$/) { print "good entry\n"; } else { print "bad entry\n"; }
Re: Check for Positive Integer entry only
by chrism01 (Friar) on May 09, 2007 at 22:59 UTC
    # +ve int, not inc zero, optional space, optional sign $var1 =~ s/^\s+//; # leading whitespace $var1 =~ s/\s+$//; # trailing whitespace if( $var1 =~ /^[+]?\d+$/ && $var1 != 0 ) { print "+ve int\n"; }
    Cheers
    Chris
Re: Check for Positive Integer entry only
by shobhit (Sexton) on May 09, 2007 at 19:29 UTC
    Do we absolutely need a RE to check for positive integer? Can't we simply check for >0 ?

      Can't we simply check for >0?

      print 'no' if '1a' > 0; print 'no' if .1 > 0;
        Get the point now.
        But this also means, that we may never be sure of the result of comparison operator.

        Is there anyway, such
        int 'comparison operator' int # returns the actual result
        int 'comparison operator' string # returns an error

        We could check for the type of both before comparing them, of course. But, thats not the point....
        Something more simple than that, just compare and get the result or an error as the case may be.

      Close. I think ($_ eq int($_) && $_ > 0) will work as a condition though.

      use strict; use warnings; my @tests = qw/12 1a 4 -3 0 0.1 .1/; for (@tests) { print "$_ => "; no warnings qw/numeric/; if ($_ eq int($_) && $_ > 0) { print 'ok'; } else { print 'bad'; } print "\n"; } __END__ C:\Perl\test>perl int_test.pl 12 => ok 1a => bad 4 => ok -3 => bad 0 => bad 0.1 => bad .1 => bad

      ___________
      Eric Hodges
        use strict; use warnings; use Test::More; my @good = qw( 12 1 +1 1234 ); my @bad = qw( 1a -3 0.1 .1 0 +0 -0 ); plan 'tests' => scalar @good + scalar @bad; ok( is_int( $_ ), "[$_] is int" ) for @good; ok( ! is_int( $_ ), "[$_] is not int" ) for @bad; sub is_int { return ( $_[0] eq int( $_[0] ) && $_[0] > 0 ); } __END__ 1..11 ok 1 - [12] is int ok 2 - [1] is int not ok 3 - [+1] is int # Failed test '[+1] is int' # in perlmonks.pl at line 14. ok 4 - [1234] is int Argument "1a" isn't numeric in int at perlmonks.pl line 18. ok 5 - [1a] is not int ok 6 - [-3] is not int ok 7 - [0.1] is not int ok 8 - [.1] is not int ok 9 - [0] is not int ok 10 - [+0] is not int ok 11 - [-0] is not int # Looks like you failed 1 test of 11.

        Oops. I should have named that is_positive_int, etc.