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

Respected Monks,

Please let me know if there is a way that I can insert the logical OR or AND operator in an if loop.

Reason to do this is, I have a condition wherein I need to check if a string contains colon ":" or if the string is not equal to 16 characters, the script should exit.

I know I can write if elsif else, but, am trying to find a way if the || operator, or the && operator can be inserted in an if loop so that I can say something like the following. I tried it out, but its not working.

if ($string=~m/:/g || length($string)!=16) { print "Either : already in string on the length is invalid\n"; exit; } else { work on that string }

Please let me know. Kindly note that I am not a trained programmer and though I have some extremely primitive C knowledge, I am a newbie to Perl, so any mistakes/misconceptions on my understanding of the if loop, please pardon me.

Perl Version - (v5.14.2) MSWin32-x64-multi-thread on Windows 7 64 Bit.

Replies are listed 'Best First'.
Re: How to insert || and && in an if loop
by Eliya (Vicar) on Dec 17, 2011 at 19:32 UTC

    Using logical OR or AND works fine in if-conditions. but you most likely don't want to use the /g option in the regex match. Reason is this:

    my $string = "foo:bar:baz:quux"; for (1..10) { print "$_\n"; if ($string=~m/:/g || length($string)!=16) { print "Either : already in string on the length is invalid\n"; } } __END__ 1 Either : already in string on the length is invalid 2 Either : already in string on the length is invalid 3 Either : already in string on the length is invalid 4 5 Either : already in string on the length is invalid 6 Either : already in string on the length is invalid 7 Either : already in string on the length is invalid 8 9 Either : already in string on the length is invalid 10 Either : already in string on the length is invalid

    Note that it doesn't match on the 4th and 8th iteration. See the description of the match operator in perlop for why.

      ... you most likely don't want to use the /g option ... [emphasis added]

      For advice to a monk inexperienced in both programming in general and Perl in perticular, I would promote "most likely don't" to "do not" (including the boldface) for the reason that your example demonstrates and perlop discusses: that it sets up a subtle (but still lethal!) pitfall that may ensnare even the most puissant monk. In fact, I would go farther and say that an inexperienced monk should never use the /g regex modifier unless he or she knows exactly why it is being used. (In fact, this would not be bad general advice for monks and programmers of every level of experience!)

Re: How to insert || and && in an if loop
by hbm (Hermit) on Dec 17, 2011 at 19:29 UTC

    No need for the 'g' modifier.

    Why not die with a message, rather than print and exit?

    Other than that, assuming your else condition is pseudo-code, it looks like it ought to work.

    But I'd probably do something like this:

    die "Either : already in string on the length is invalid\n" if $string =~ /:/ || length($string)!=16; print "work on that string"

    Update: Another non-working option:

    die "..." if $string =~ /:|.{17}/;

    See below. Thanks AnomalousMonk.

      die "..." if $string =~ /:|.{17}/;

      This accepts all strings less than 17 characters. perl514 wants only strings exactly 16 characters.

      >perl -wMstrict -le "my $string = 'foo'; ;; die '...' if $string =~ /:|.{17}/; ;; print qq{processing '$string'}; " processing 'foo'
Re: How to insert || and && in an if loop
by perl514 (Pilgrim) on Dec 18, 2011 at 06:22 UTC
    Respencted Monks, Thank you for taking time to reply. I want to try the insertion of || Operator because currently my script looks like this:
    #!/usr/bin/perl use warnings; use strict; print "Enter a for lowercase and colons. b to do it the other way around. q to quit "; my $choice = 0; my $wwn = 0; chomp ($choice = <STDIN>); if ($choice eq "a") { until ( $wwn eq "q") { print "Enter the wwn or q to quit: "; chomp ($wwn=<STDIN>); if ($wwn=~m/:/g) { print "WWN already contains :\n"; exit; }#closing for if ($wwn=~m/:/g) elsif (length($wwn)!=16) { print "Invalid WWN Length\n"; exit; }#closing for elsif (length($wwn)!=16) else { my @wwn = unpack ("(a2)*", lc($wwn)); @wwn = join (":", @wwn); print "@wwn\n"; } #closing for lowering case and adding : in wwn. }#closing for until ( $wwn eq "q") }#closing for if choice =a elsif ($choice eq "b") { until ($wwn eq "q") { print "Enter the wwn with : or q to quit: "; chomp ($wwn=<STDIN>); $wwn =~ s/://g; print lc($wwn), "\n"; } #closing for until ($wwn eq "q") }#closing for if choice =b elsif ($choice eq "q") { exit; }#closing for elsif ($choice eq "q")

    What the script does is, it takes a 16 character long wwn and if I need it to be in lowercase and a ":" needs to be inserted, it does that. The second option is it removes the ":".

    I need this functionality as these strings are WWNs aka World Wide Names that are used in the SAN Connectivity. Sometimes I need them in lowercase with ":" in them and sometimes I need them without ":". When I login to Cisco SAN Switches and search for these, I get them with ":". Other places where I need to put them, they should go without the ":".

    My foremost apologies if the indentation is not good/confusing or if there are too many comments. I am newbie and hence still trying to come to terms with the way scripts are written. Please note that I have tried to present the script in the forum in the best possible manner and kindly pardon my mistakes.

    Please direct me to pointers or guides where I can read from and improve on this script. If there is any guide or any article that shows how to write scripts in a better way indentation wise etc, kindly let me know. All of you have been very helpful and without your help, I would not be able to enjoy Perl.

    Perl Version - (v5.14.2) MSWin32-x64-multi-thread on Windows 7 64 Bit.

      There are many ways that code could be tidied up, but keeping the logic similar I'd rewrite it as:

      #!/usr/bin/perl use warnings; use strict; print <<HEREDOC; Enter: a for lowercase and colons. b to do it the other way around. q to quit HEREDOC while (my $choice = lc <>) { chomp $choice; last if $choice eq 'q'; if ($choice !~ /^[ab]$/) { print "a, b or q expected: "; next; } my $wwn = lc <>; if ($choice eq 'b') { $wwn =~ s/://g; print "$wwn\n"; next; } if (-1 < index $wwn, ':') { print "WWN already contains :\n"; next; } if (16 != length $wwn) { print "WWN must be 16 characters\n"; next; } if ($wwn =~ /^[a-f0-9]/) { print "Non-hex characters are not allowed in WWN\n"; next } print join (':', unpack ("(a2)*", $wwn)), "\n"; }

      Note that the nesting has become shallow. Each of the tests is simple and the code associated with them is trivial. Early exits (in this case next and last) are used extensively to avoid the need for else clauses and consequent nesting.

      Update: Fixed hex digit match regex - thanks AnomalousMonk

      True laziness is hard work
      Hi,

      I would save wwn in raw format (without any ":"), and then I would format it with a function which do it (maybe with a parameter which indicate which format you want)

      I would recommend you using given statement (not if / else jungle)

      Regards,

Re: How to insert || and && in an if loop
by perl514 (Pilgrim) on Dec 19, 2011 at 07:10 UTC

    Venerated Monks,

    Thank you for your kind guidance.

    Sir GrandFather,

    I have no words to express my gratitude. Your code is a learning chapter for me. HEREDOCs, regex stuff that I really need to look into, wow....this is one powerful language and you are all extremely knowledgeable and helpful.

    I could only up vote you just once. This guidance of yours is worth many up votes sire.

    Perl Version - (v5.14.2) MSWin32-x64-multi-thread on Windows 7 64 Bit.