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

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

I'm trying to check the value and make sure its a whole number between 1 and 75, so 1,2,3,4 but not 20.5 or 97 or -5, etc. In my head it makes sense, I've done both separately before, whats missing to make it work in this context? Better way to do it? I messed with it a bit with no luck so I come seeking wisdom :)
if ($_ =~ /\something(.*)somethingelse/i){ if($1 => 1 and $1 <= 75 and /\d{1}-\d{2}/) { ... } }

Replies are listed 'Best First'.
Re: Matching numeric value between two digits
by toolic (Bishop) on Feb 04, 2013 at 21:37 UTC
    How's this?
    use warnings; use strict; for (qw(1 2 3 4 20.5 97 -5)) { if (($_ >= 1) and ($_ <= 75) and (!/\./)) { print "$_ yes\n"; } else { print "$_ no\n"; } } __END__ 1 yes 2 yes 3 yes 4 yes 20.5 no 97 no -5 no
      The code works, just not in my context, which is much the same as mine, it seems to be something with pulling the value from between the keywords and putting it in $1 but that's what I need in this case. Toying a bit more I ended up with this, which works for my need even if a bit clumsy, can anyone shed light on why it needs to be set in a new variable? The same digit check used in the primary check on $1 just won't work for me but this does.
      if ($_ =~ /\something(.*)somethingelse/i){ if (($1 >= 1) and ($1 <= 75)) { $a = $1; if ($a =~ /^\d+$/){ ... } } }

        You weren't doing the check on $1 in your original code.

        if($1 => 1 and $1 <= 75 and /\d{1}-\d{2}/) { ... }

        The /\d{1}-\d{2}/ is done on $_, not $1.

        BTW you could just do the whole-number check right away:

        if ($_ =~ /\something(\d*)somethingelse/i){ if($1 => 1 and $1 <= 75) { ... } }
Re: Matching numeric value between two digits
by SuicideJunkie (Vicar) on Feb 04, 2013 at 21:48 UTC

    Is 70.00 ok?

    If so, I'd suggest a simple and $1 == int($1)

      Sadly no, I only want it to accept a whole number and no decimals; if they entered 20.00 i'd wait it to fail to no.
Re: Matching numeric value between two digits
by ww (Archbishop) on Feb 05, 2013 at 01:41 UTC
    The greedy death-star is another problem. You need to limit it:
    C:\>perl -E "my $num ='abcd23.5fghi';if ($num =~ /[a-z]+(.*?)[a-z]/i){ + say $1;}" 23.5 /^\
    The above is OK (Yes, I know OP wants only INTs, but this is a minimal example of the death-star problem) when the greedy ".*" is limited by the "?" but it's definitely not what the OP seems to want if the limit ("?") is omitted.
    C:\>perl -E "my $num ='abcd23.5fghi';if ($num =~ /[a-z]+(.*)[a-z]/i){ +say $1;}" 23.5fgh # not what OP seems to want
    Also rather than the clumsy "/\d{1}-\d{2}/" you might wish to use "/[0-9]+/" and, more verbosely this also works (but is a far less stringent regex):
    C:\>perl -E "my $num ='abcd23fghi'; my $intermediate; if ($num =~ /[a- +d]+(\d+)[f-z]+/) {$intermediate = $1;} if ($intermediate =~ /[0-9]+/ +){ say $intermediate;}" 23
    ... whereas this fails:
    C:\>perl -E "my $num ='abcd23.777fghi'; my $intermediate; if ($num =~ +/[a-d]+(\d+)[f-z]+/) {$intermediate = $1;} if ($intermediate =~ /[0-9 +]+/ ){ say $intermediate;}" (no output)

    The previous discussion should make it easy to identify the cause of the failure.

Re: Matching numeric value between two digits
by 7stud (Deacon) on Feb 05, 2013 at 00:43 UTC
    use 5.012; my $num = 2; if ($num => 2) { say 'yes'; } $num = 1; if ($num => 2) { say 'yes'; } --output:-- yes yes
    my %hash = ( 'a' => 2, 'b' => 3, 'c' => 4, ); use Data::Dumper; say Dumper(\%hash); --output:-- $VAR1 = { 'c' => 4, 'a' => 2, 'b' => 3 };
    Another problem with your code is: you misspelled greater-than-or-equal-to.
Re: Matching numeric value between two digits
by BillKSmith (Monsignor) on Feb 05, 2013 at 04:09 UTC

    Match only valid patterns.

    /known string([1-6]?\d|7[0-5])another known string/
    Bill
Re: Matching numeric value between two digits
by 7stud (Deacon) on Feb 05, 2013 at 02:11 UTC

    Also rather than the clumsy /\d{1}-\d{2}/ you might wish to use /[0-9]+/

    Of course, those regexes don't match the same things:

    use strict; use warnings; use 5.012; my $str = "8-91"; if ($str =~ /(\d{1}-\d{2})/) { say $1; } if ($str =~ /([0-9]+)/) { say $1; } --output:-- 8-91 8
    The op's regexes don't make much sense.