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

I have my code looking for $expire not being equal to 1..14
I've tried:
if ($expire ne (1||2||3||4||5||6||7||8||9||10||11||12||13||14)) {die " +Don't tamper with me!";}

if ($expire <=>1||2||3||4||5||6||7||8||9||10||11||12||13||14) {die "Don't tamper with me!";}

...and various other combos.

So if $expire is anything else besides the numbers 1 thru 15 the program will die. What is wrong with this test? Where is my logic going wrong?

Replies are listed 'Best First'.
Re: IF Statement Testing
by Zaxo (Archbishop) on May 14, 2005 at 06:02 UTC

    How about this? die "Don't tamper with me" if $expire >= 1 and $expire <= 14; If you need it to be an integer you can throw in $expire == int $expire

    After Compline,
    Zaxo

Re: IF Statement Testing
by davido (Cardinal) on May 14, 2005 at 05:53 UTC

    Several problems. First, <=> is a three-state operator. It has different return values for less than comparisons, greater than, and equal to. It's primarily used for numeric comparisons in sort routines. You should be using !=

    The next problem is that you cannot chain 1||2||3||4||5 like that. That's like saying "If $expire is not equal to 1, or if two, or if three, or if four, etc." In other words, the comparison only binds to $expire != 1.

    To write that correctly, the way you're trying to test, it would be:

    if( $expire != 1 or $expire != 2 or $expire != 3...... )

    ...and so on. But how about this instead?

    if( $expire != int $expire or $expire < 1 or $expire > 14 ) { die "Don't tamper with me!\n"; }

    You could also do it like this, using a hash slice:

    my %test; @test{ 1 .. 14 } = (); unless( exists $test{$expire} ) { die "Don't tamper with me!\n"; }

    In all my examples, I've assumed that you want to reject non-integers.


    Dave

      You flipped the logic here.
      if( $expire != 1 or $expire != 2 or $expire != 3...... )
      should be
      if( $expire != 1 and $expire != 2 and $expire != 3...... )
      OTOH, this can also be solved by a hash lookup


      holli, /regexed monk/
Re: IF Statement Testing
by !1 (Hermit) on May 14, 2005 at 06:02 UTC
    if ($expire < 1 ||  14 < $expire || int $expire != $expire) { die "Don't tamper with me!"; } or
    my %check; undef @check{1..14}; if (! exists $check{$expire}) { die "Don't tamper with me!"; }
    or
    if ($expire !~ /^(?:[1-9]|1[0-4])$/) { die "Don't tamper with me!"; }
    or
    use Quantum::Superpositions; if ($expire != any(1..14)) { die "Don't tamper with me!"; }

    and many other ways.

Re: IF Statement Testing
by gaal (Parson) on May 14, 2005 at 06:13 UTC
    In Perl6 (works with current Pugs):

    if $expire ~~ none(1 .. 14) { ... }

      But what I find more interesting is that the OP totally intuitively discovered junctions, and almost perfectly found the right syntax as well. Look at this variant:
      if ($expire !~ any(1|2|3|4|5|6|7|8|9|10|11|12|13|14)){...}

      Update: thanks gaal for lighting me up, although, I can not entirely grasp, what is the problem above...:-). Intuitively, $x ~~ none(...) should give the same result as $x !~ any(...), or at least, my intuition suggests this...

      Anyway, here is an updated syntax that even more resembles to the OP's idea, and it actually works right in Pugs:

      if (!($expire ~~ 1|2|3|4|5|6|7|8|9|10|11|12|13|14)) {...}
      Interestingly, Pugs requires parens around the if condition. Is this a bug?
        That unfortunately doesn't work, because there always exists an element in the junction so that $expire !~ it. The condition is always true.
Re: IF Statement Testing
by gopalr (Priest) on May 14, 2005 at 05:44 UTC

    Change your code as follows

    if ($expire !~m#^(1|2|3|4|5|6|7|8|9|10|11|12|13|14)$#) { die "Don't tamper with me!"; }

    Update:: Remove doubel "|" to single

      Except it should be single "|"s in your regexp, not "||"s

      But why use a regexp at all?

      if ($expire < 1 || $expire > 14) { die "Don't tamper with me!"; }
Re: IF Statement Testing
by prasadbabu (Prior) on May 14, 2005 at 05:42 UTC

    <=> is wrong.
    you can use regular expression !~

    $expire !~m/^(1|2|3|4|5|6|7|8|9|10|11|12|13|14)$/

    updated

    Prasad

Re: IF Statement Testing
by northwind (Hermit) on May 14, 2005 at 10:41 UTC

    If you're looking to exclude specific values (not necessarily contiguous), then here is another way to solve your problem:

    if (scalar grep { $expire ne $_ } @values) { die "Don't tamper with m +e!"; }

    Where @values is filled with the values you want to check for.  Also, if you are doing only numbers you can change the ne test to a != test.

    Update:  Added italics to "another" to emphasize TMTOWTDI.  For further insight into TMTOWTDI (and why algorithms, unlike men, are not all created equal), might I suggest reading the chain of replies resulting from this post.

      Yes, you can use grep, but that means doing a linear search that only exits after stepping through all elements, even if the first element found satisfies the criteria. If this conditional is to be tested repeatedly, doing a hashtable lookup is more elegant and more efficient...and depending on who you ask, easier on the eyes.


      Dave

        Yes, I agree using a hash is the best implementation.  Dark, wierd, and frought with perils would be the situation where grep would be the best choice.  TMTOWTDI doesn't mean all algorithms are equal... :)