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

Fellow Monks, forgive my silly question, but I am doing a web app, containing Date fields, at runtime @list contains the values:
'2002-11-09'
''
My problem is that my flag is being set here, whether I use the short-circuiting '||' or the other operator 'or'.
As you can see below, I am trying to make sure the date has the proper format, or is empty. With the regex alone, I have no problems ensuring the date format is correct. My problem is when I attempt to use the or operator.

Please explain this problem? Code is as follows...
foreach (@list) {if (! /\d{4}\-\d{2}/-/d{2}/ or $_ ne '') {$Flag=1 +;}} if ($Flag ==1) {print "The date fields MUST be filled out correctl +y!";exit;}

Thanks!

Replies are listed 'Best First'.
Re: "or" or "||" problems
by tachyon (Chancellor) on Nov 06, 2002 at 22:32 UTC

    First your regex is broken as you have got some / and \ mixed up. Your regex is seen by perl as

    m/\d{4}\-\d{2}/ - m/d{2}/

    This is unfortunately valid as m// will return a true value if it matches (1) and false (0) if it does not and you can perform integer math on these results. This code should do what you want. You don't need the flag as you can just fail on the first error rather than going through the whole list every time....

    for (@list) { next unless $_; unless ( m#\d{4}\-\d{2}\-\d{2}# ) { print "$_ is invalid, the date fields MUST be filled out corre +ctly!"; exit; } }

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

      Thanks so much. The regex was b0rked, yes. :) Although my actual code has it correct. -That's what I get for posting after boiling my brain. <grin>
      I should have thought about the 'next unless $_'. That makes much more sense than what I was doing.
      Also, to avoid the ridicule about my flag being global that is mentioned below, it wasn't. :) I just neglected to post the other declarations in the sub that were outside my loop.

      Anyways, thanks again. :)

        You could get really fancy if you wanted. When validating input via CGI I ususally use $err_msg as a flag. I use it like this:

        ############ VALIDATE USER DATA ############# my $err_msg = ''; # check valid date format $err_msg .= "<p>Wrong date format '$date', use YYYY-MM-DD\n" unless $date =~ m#(\d{4})\-(\d{2})\-(\d{2})#; my $year = $1 || ''; my $month = $2 || ''; my $day = $3 || ''; # check year $err_msg .= "<p>Invalid year '$year'\n" unless $year > 1970 and $year +< 2100; # check month # blah # check day # blah # check other input adding error messages to $err_msg do { show_error_page($err_msg); exit } if $err_msg; ########### ONLY GET HERE IF INPUT VALID ########## do_work()

        I like this because you validate all your input and respond with a comprehensive error message(s). You use $err_msg (which contains elpanatory error text) as the flag, killing two birds with one scalar.

        cheers

        tachyon

        s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: "or" or "||" problems
by Zaxo (Archbishop) on Nov 06, 2002 at 22:47 UTC

    You have a couple of '/' for '\' typos in the regex, and from your description, you should use the eq operator instead of ne. Also your $Flag variable is global and not reset, so if the first element of @list passes, the print and exit sequence is never reached.

    Does this work for you?

    for (@list) { if (! /\d{4}\-\d{2}\-\d{2}/ or $_ eq '') { die 'The date fields MUST be filled out correctly!', $/; } }

    I changed the print; exit; sequence to die so that throw/catch can be done with eval, or a __DIE__ handler invoked. That will print the message to STDERR instead of the selected output handle.

    You seem to suggest that or does not short-circuit. False, || and or only differ in operator precedence.

    After Compline,
    Zaxo

Re: "or" or "||" problems
by FamousLongAgo (Friar) on Nov 06, 2002 at 22:36 UTC
    Your big problem is that the regular expression is broken. Notice the direction of the slashes:

    BAD: /\d{4}\-\d{2}/-/d{2}/
    GOOD: /\d{4}\-\d{2}-\d{2}/

    Here is a more Perlish way to do what you are looking to do:
    print "Error!" if grep { !( /\d{4}-\d{2}-\d{2}/ or $_ eq '' ) } @list;

    This is saying "Iterate through the array. Give me any elements that do not 1) match the regex and 2) have zero length. In scalar context, you get the number of offending entries. In list context, you get the entries themselves.
Re: "or" or "||" problems
by Enlil (Parson) on Nov 06, 2002 at 22:19 UTC
    I think what you have and what you want are two different things.

    What you want (from your post, I hope I am not misreading it): is to check if the date string is the way you want or is empty. What you conditional states is: if the date string is not the way I want OR $_ is NOT EQUAL to '' then set the $Flag variable

    What I think you want is: if the date string is not the way I want AND then $_ is not equal to '', then set the flag.

    if (! /\d{4}\-\d{2}/-/d{2}/ and $_ ne '')

    or

    unless ( /\d{4}\-\d{2}/-/d{2}/ or $_ eq '')

    Update: As posted below, you will want to look at the regex as well, as I unfortunately did not bother to check to make sure that was working when I was looking at your code (and hence made no modifications to it). Thanks tachyon

    -enlil

Re: "or" or "||" problems
by Ananda (Pilgrim) on Nov 07, 2002 at 04:35 UTC
    I think, this should help you, from what I understand from ur query. foreach (@list) {if (! /\d{4}\-\d{2}\-\d{2}/ && $_ ne '') {$Flag=1;}} if ($Flag ==1) {print "The date fields MUST be filled out correctly!"; exit;} Hope it Helps. Cheers!!!! Anandatirtha
      A little correction , since you need to validate each element in the @list array. the pattern checking sequence must be within the foreach loop. foreach (@list) {if (! /\d{4}\-\d{2}\-\d{2}/ && $_ ne '') {$Flag=1;} if ($Flag ==1) {print "The date fields MUST be filled out correctly!"; exit;}} This is about it. Anandatirtha