Copas
Copas

Reputation: 5952

Perl regex not breaking out of until loop as expected

When I print the result of the regex I am attempting to use to control the until loop it gives me the 1 or null I am expecting. Why is it that the code below won't work but if I uncomment the fifth line it works fine?

print("Please enter 1, 2, 3 or 4 : ");
my $channelSelection = "";

until ($channelSelection =~ /^[1-4]$/) {
    chomp(my $channelSelection = <STDIN>);
    #last if ($channelSelection =~ /^[1-4]$/);
    print ("Invalid choice ($channelSelection) please try again: ") 
        if ($channelSelection !~ /[1-4]/);
}

I'm sure this has been solved elsewhere but was unable to find it with search. Pointing me in the right direction would be great.

I would normally do something like.

print("Please enter 1, 2, 3 or 4 : ");
my $channelSelection = "";
while (1) {
    chomp(my $channelSelection = <STDIN>);
    last if ($channelSelection =~ /^[1-4]$/);
    print ("Invalid choice ($channelSelection) please try again: ") if ($channelSelection !~ /[1-4]/);
}

But I'm trying to get away from the infinite loops.

Upvotes: 7

Views: 585

Answers (5)

Alan Haggai Alavi
Alan Haggai Alavi

Reputation: 74282

You have redeclared $channelSelection locally within the until loop. That way, its value will be lost every time the loop executes. So the regular expression will not match as the then value of $channelSelection will again be equal to "".

Removal of my from within the loop will solve the issue.

Upvotes: 11

Anon
Anon

Reputation: 326

This is more of a style issue (and since you can't install modules, it doesn't help you), but I just wanted to point out that when checking for fixed values, using a regex is probably not the best solution.

This is is what I would do:

use List::MoreUtils;

my @allowed_values = qw( 1 2 3 4 );

# get $answer from prompt.

if(any { $_ == $answer } @allowed_values) {
    # All is good.
}

Might come in handy some other time.

Upvotes: 2

user80168
user80168

Reputation:

The best solution for getting input from user is to use IO::Prompt module. It supports repetitions, validations, menu system and much more.

Upvotes: 3

Sinan &#220;n&#252;r
Sinan &#220;n&#252;r

Reputation: 118166

How about not worrying about it?

#!/usr/bin/perl

use strict;
use warnings;

use Term::Menu;

my @channels = qw( 1 2 3 4 );

my $prompt = Term::Menu->new(
    aftertext => 'Please select one of the channels listed above: ',
    beforetext => 'Channel selection:',
    nooptiontext =>
        "\nYou did not select a valid channel. Please try again.\n",
    toomanytries =>
        "\nYou did not specify a valid channel, going with the default.\n",
    tries => 3,
);

my $answer = $prompt->menu(
    map { $_ => [ "Channel $_" => $_ ] } @channels
);

$answer //= $channels[0];

print "$answer\n";

__END__

Upvotes: 6

Artem Russakovskii
Artem Russakovskii

Reputation: 22023

The problem here is you're re-declaring the $channelSelection within the loop but the outside of the loop keeps the old value. Remove the "my" from the inner loop.

Upvotes: 18

Related Questions