输入错误时while循环无限

While-loop infinite when wrong input is entered

我正在创建一个包含 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();

无限循环给出了这个:

No such name found :-(, try once again

No such name found :-(, try once again

No such name found :-(, try once again

No such name found :-(, try once again

并继续....

提前致谢:-)

只有在找到名称时才重置 $var。

移动这条线...

$var = 0

if/else之后。

你还需要移动这条线...

chomp(我的 $name = );

while 循环内部,if 之前。

使用这个,简化,不需要循环(递归函数):

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();

第 20 行,一个“;”不见了

它不起作用,因为找不到该名称时您需要再次询问该名称,否则它将循环($var 不会更改为 0)

简单示例:

else{
    print "No such name found :-(, try once again\n";
    chomp($name = <STDIN>);
}

您的代码中存在逻辑错误。出于演示目的,我将不再使用 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

^CCommand terminated 行来自当我最终按 -c 终止 运行 时。)

此时,通过打印最近从 <DATA> 读取的名称的附加信息,很容易看出我们只查看了 John。但为什么?因为您的循环不从 <DATA> 文件句柄中读取。你在循环之外这样做。

这里有一个更波斯语的方式来完成你想做的事情:

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。我们把它赋值给$namechomp它,然后检查John是否作为hash key存在。它没有,所以我们打印名称并继续下一次迭代。在第二次迭代中,<DATA> 读取 Dave\n,将其压缩,并检查它是否存在。它没有,所以我们打印名称并继续下一次迭代。

在第三次迭代中,我们 <DATA> 获得 Maria\n,对其进行压缩,并检查哈希键 Maria 是否存在。它确实如此,因此它打印与该键关联的值,然后点击 last 语句。 last 告诉流控制立即退出封闭循环。循环主块中的其余行将被跳过,并且不再有迭代。它通常比示例代码中的 $var 等哨兵变量更清晰,因为代码的 reader 不需要跟踪变量可能处于的状态。

所以简而言之,你的错误是只从输入文件句柄读取一次,然后期望你的循环在进入循环之前遇到 $name 中的变化,尽管它只被分配了一次。解决方案是将读取的文件移动到循环中。

此模式记录在 perldoc perlvar 中,我鼓励您花几分钟阅读以更好地熟悉这门语言。

更新:我确实看到了一个答案,其中再次调用 main() 被用作迭代读取文件的一种方式,这没有错。但是在真实的脚本中 main() 可能会变大,当发生这种情况时,文件读取循环要么需要再次成为显式循环,要么被分解为另一个可以调用自身的子例程。此外,while 循环方法是一种惯用或常见的解决方案,更可能在其他人编写的代码中找到。使用递归读取文件是一种不太常见的模式。