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

I am no more than 2-3 weeks into perl and I am trying to better understand while () loops a tad better.Here is a snippet from of a code I wrote up to work on my conditionals and loops:
while () { print "Are you having/had a good, bad, or iffy day $name?: "; chomp ($input = <STDIN>); if ($input eq 'good') { print "Glad you are doing well!\n";last;} elsif ($input eq 'bad') { print "Oi, that's not good to hear!\n";last;} elsif ($input eq 'iffy') { print "At least you're undecided...still hope after all.\n +";last;} } print "\n";
In this block, I really wanted to do something like:
elsif ($input ne 'good'|| 'bad'|| 'iffy') { next;}
and get rid of all the {last;} at the end of each elsif statement. The problem is that I can't seem to get this or operator to work properlly and I was hoping someone could possibly point me in the right direction.
Thank you in advance.

BTW, the full code can be found at in my sketchpad titled "Practicing Conditionals"
code in sketchpad updated 2005.12.02


"Es gibt mehr zu Leben als Bücher, kennen Sie. Aber nicht viel mehr " -(Der Smiths)

Replies are listed 'Best First'.
Re: A better understanding of while () loops
by xdg (Monsignor) on Dec 01, 2005 at 16:33 UTC

    Welcome to Perl!

    First, rather than rewriting your looping and logic, let's just cover the expression for checking alternatives and I think you can work out the rest as part of your own experimentation. You can do it like this (parens added for clarity):

    ($input ne 'good') && ($input ne 'bad') && ($input ne 'iffy')

    You may not be ready for regular expressions quite yet, but they provide another approach to matching alternatives

    ! ( $input =~ /good|bad|iffy/ )

    You can read that =~ bit as "input matches good or bad or iffy" in the way we idiomatically mean that in English. Negating that can also be done all in one as this:

    $input !~ /good|bad|iffy/

    Best of luck

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

      Thank you for making me feel welcome!
      "Es gibt mehr zu Leben als Bücher, kennen Sie. Aber nicht viel mehr " -(Der Smiths)
Re: A better understanding of while () loops
by wfsp (Abbot) on Dec 01, 2005 at 16:38 UTC

    elsif ( $input ne 'good' and $input ne 'bad' and $input ne 'iffy' ){ next; }
    or:
    elsif ( $input !~ /good|bad|iffy/ ){ next; }
    or consider a lookup hash:
    my %lookup = ( good => undef, bad => undef, iffy => undef, ); # and then within your loop next unless exists $lookup{$input};

    update: added a missing brace
    update 2: changed =~ to !~ in second snippet

Re: A better understanding of while () loops
by fishbot_v2 (Chaplain) on Dec 01, 2005 at 16:42 UTC

    If you are looking to match exact words, then you might consider solving this problem with a hash instead:

    my %moods = ( good => "Glad you are doing well!\n", bad => "Oi, that's not good to hear!\n", iffy => "At least you're undecided...still hope after all.\n", ); while (1) { print "Are you having/had a good, bad, or iffy day $name?: "; chomp( my $input = <STDIN> ); # assuming case-insensitive: next unless exists $moods{ lc( $input ) }; print $moods{ lc( $input ) }; last; }

    update: wfsp beat me to it.

Re: A better understanding of while () loops
by Perl Mouse (Chaplain) on Dec 01, 2005 at 16:52 UTC
    A few things. First, if you want to compare a value against a few others, you just have to repeat it:
    $input ne 'good' && $input ne 'bad' && $input ne 'iffy'
    Note the use of && instead of ||. If you'd use || the condition would be true if $input was both 'good', 'bad' and 'iffy' at the same time. This can't happen.

    However, in your example, you don't need this test at all. You've already covered the cases for 'good', 'bad' and 'iffy', so by the time you get here, you already know $input isn't containing any of them. Write your chain as:

    if ($input eq 'good') {print "..."} elsif ($input eq 'bad') {print "..."} elsif ($input eq 'iffy') {print "..."} else {next} last;
    Now, if all you do is printing strings in your cases, you could have used a hash, and simple print the appropriate value from the hash, but that draws away into details not related to the control flow questions you have.

    Finally, your loop stinks. You have a while loop whose guard is always true, but then inside you read unconditionally from standard input. What if there's nothing more to read?

    I would write that as:

    print "Are you having/had a good, bad, or iffy day $name?: "; while (my $input = <>) { chomp $input; if ($input eq 'good') {print "..."; last} elsif ($input eq 'bad') {print "..."; last} elsif ($input eq 'iffy') {print "..."; last} print "Are you having/had a good, bad, or iffy day $name?: "; }
    Note that I preferred to repeat the 'last' in the various blocks, and that I got rid of the 'next' statement. This code stops processing input if there's no more input - that's what the while is doing.

    Purists may object to the duplication of the code - the printing of the prompt happens twice. If so, one could use IO::Prompt or write something like:

    while (do {print "...."; defined (my $input = <>)}) { if (...) {...; last} elsif (...) {...; last} elsif (...) {...; last} }
    But I prefer the duplication of code over the added complexibility.
    Perl --((8:>*
Re: A better understanding of while () loops
by sub_chick (Hermit) on Dec 01, 2005 at 17:02 UTC
    I appreciate the help from each and everyone of you and I am going to experiment with each of your suggestions and hopefully update my sketchpad with a more sufficient code and and learn alot more whilst doing so. Thank you for the help.

    "Es gibt mehr zu Leben als Bücher, kennen Sie. Aber nicht viel mehr " -(Der Smiths)
Re: A better understanding of while () loops
by psychotic (Beadle) on Dec 01, 2005 at 16:40 UTC
    Or you could alternativelly try something like the following:
    my @acceptable = ('good', 'bad', 'iffy'); while(<>) { chomp; my $input = $_; foreach (@acceptable) { next unless $_ eq $input; print "You are feeling $_!"; undef $input; last; } unless( $input) { print "You didn't give an acceptable answer! Try again:\n"; } }
    Update: fixed a small error.