Бесконечный цикл при вводе неправильного ввода - PullRequest
0 голосов
/ 13 октября 2018

Я создаю хэш, который содержит имена 4 человек.Я хотел бы, чтобы пользователь под одним из имен и получить профессию.В то же время я хочу, чтобы программа продолжала запрашивать ввод имени, если ввод имени был неправильным.Однако когда я запускаю свой код, он переходит в бесконечный цикл while, когда имя не найдено.Любые подсказки, как это исправить?

use strict;
use warnings;

sub main {

my %profession = (
    "Emelie"  => "Economist",
    "Hugo" => "Scientist",
    "Maria"  => "Accountant",
    "Linnéa"  => "Medical Doctor",
    );

print ("Enter first name: ");
chomp(my $name = <STDIN>);

my $var = 1;
while ($var) {
    if (exists $profession{$name}) {
        print "The profession is: ", $profession{$name}, "\n";
        $var = 0
    }
    else {
        print "No such name found :-(, try once again\n";
    }

}

}
main();

Бесконечный цикл дает следующее:

Такое имя не найдено :-(, попробуйте еще раз

Такое имя не найдено :-(, попробуйтееще раз

Имя не найдено :-(, попробуйте еще раз

Имя не найдено :-(, попробуйте еще раз

и продолжите ....

Заранее спасибо: -)

Ответы [ 4 ]

0 голосов
/ 13 октября 2018

В вашем коде логическая ошибка.В целях демонстрации я перейду от использования STDIN в качестве дескриптора ввода вместо его использования DATA, чтобы я мог запекать некоторые тестовые данные.Я также исключу внешнюю подпрограмму, поскольку она не имеет отношения к обсуждению.

use strict;
use warnings;

my %profession = (
    Emelie    => 'Economist',
    Hugo      => 'Scientist',
    Maria     => 'Accountant',
    Linnéa    => 'Medical Doctor',
);

chomp(my $name = <DATA>);

my $var = 1;
while($var) {
    if (exists $profession{$name}) {
        print "The profession for $name is $profession{$name}\n";
        $var = 0;  # This could just be the 'last' keyword.
    }
    else {
        print "No such name ($name) found. Try again.\n";
    }
}

__DATA__
John
Dave
Maria

Как видно из примеров данных, можно ожидать, что программа с правильной логикой завершит работу после третьей попытки, потому чтоMaria - это один из ваших хеш-ключей.Но если вы запустите его, вы увидите следующее:

No such name (John) found. Try again.
No such name (John) found. Try again.
No such name (John) found. Try again.
No such name (John) found. Try again.
No such name (John) found. Try again.
No such name (John) found. Try again.
No such name (John) found. Try again.
No such name (John) found. Try again.
^C
Command terminated

(строки ^C и Command terminated приходят с того момента, когда я наконец нажал -c, чтобы прекратить запуск.)

Atв этот момент, с дополнительной информацией о печати имени, которое было недавно прочитано из <DATA>, довольно легко увидеть, что мы только когда-либо смотрим на John.Но почему?Потому что ваш цикл не читает из файлового дескриптора <DATA>.Вы делаете это вне цикла.

Вот еще один способ Perlish для выполнения того, что вы хотите сделать:

use strict;
use warnings;

my %profession = (
    'Emelie'    => 'Economist',
    'Hugo'      => 'Scientist',
    'Maria'     => 'Accountant',
    'Linnéa'    => 'Medical Doctor',
);

while(my $name = <DATA>) {
    chomp $name;

    if (exists $profession{$name}) {
        print "The profession for $name is $profession{$name}\n";
        last;
    }

    print "No such name ($name) found. Try again.\n";
}

__DATA__
John
Dave
Maria

Теперь вывод будет:

No such name (John) found. Try again.
No such name (Dave) found. Try again.
The profession for Maria is Accountant

При первом цикле while мы читаем из DATA и получаем John\n.Мы присваиваем его $name, chomp, а затем проверяем, существует ли John как хеш-ключ.Это не так, поэтому мы печатаем имя и переходим к следующей итерации.На второй итерации <DATA> читает Dave\n, разбивает его и проверяет, существует ли он.Это не так, поэтому мы печатаем имя и переходим к следующей итерации.

На третьей итерации мы <DATA> получаем Maria\n, сжимаем его и проверяем, существует ли хеш-ключ Maria,Это так, поэтому он печатает значение, связанное с этим ключом, а затем выполняет оператор last.last сообщает контролю потока о немедленном выходе из замкнутого цикла.Остальные строки в главном блоке цикла пропускаются, и больше нет итераций.Она часто более разборчива, чем переменная часового типа, такая как $var в вашем примере кода, поскольку читателю кода не нужно отслеживать, в каком состоянии может находиться переменная.

Короче говоряВаша ошибка заключалась в том, что вы только один раз читали из дескриптора входного файла, а затем ожидали, что ваш цикл столкнется с изменениями в $name, несмотря на то, что он был назначен только один раз, до входа в цикл.Решением было переместить прочитанный файл, чтобы он стал частью цикла.

Этот шаблон задокументирован в perldoc perlvar, и я рекомендую вам потратить несколько минут на чтение, чтобы лучше ознакомиться с языком.

Обновление: я вижу ответ, в котором повторный вызов main() используется как средство перебора прочитанного файла, и это не так.Но в реальном сценарии main() может увеличиться, и когда это произойдет, цикл чтения файла должен либо снова стать явным циклом, либо прерваться на другую подпрограмму, которая может вызывать себя сама.Кроме того, циклический подход while представляет собой идиоматические или распространенные решения, которые чаще встречаются в коде, написанном другими.Использование рекурсии для чтения файла - менее распространенный шаблон.

0 голосов
/ 13 октября 2018

Используйте это, упрощенно, цикл не нужен (рекурсивная функция):

use strict;
use warnings;

sub main {
    my %profession = (
        "Emelie"  => "Economist",
        "Hugo" => "Scientist",
        "Maria"  => "Accountant",
        "Linnéa"  => "Medical Doctor",
    );

    print ("Enter first name: ");
    chomp(my $name = <STDIN>);

    if (exists $profession{$name}) { 
        print "The profession is: ", $profession{$name}, "\n";
    }
    else {
        print "No such name found :-(, try once again\n";
        main();
    }
}
main();
0 голосов
/ 13 октября 2018

строка 20, ";"отсутствует

оно не работает, потому что вам нужно снова спросить имя, когда оно не найдено, иначе оно будет зациклено ($ var не изменится на 0)

простой пример:

else{
    print "No such name found :-(, try once again\n";
    chomp($name = <STDIN>);
}
0 голосов
/ 13 октября 2018

Вы сбрасываете $ var, только если имя найдено.

Переместите эту строку ...

$ var = 0

После if / else.

Вам также нужно переместить эту строку ...

chomp (my $ name =);

Внутри цикла while, перед if.

...