输入错误输入时,while循环无限

时间:2018-10-13 15:17:06

标签: perl scripting-language

我正在创建一个包含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 :(得分:3)

您的代码中存在逻辑错误。出于演示目的,我将从使用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作为哈希键。不会,因此我们打印名称并继续进行下一个迭代。在第二次迭代中,<DATA>读取Dave\n,将其切短,然后检查其是否存在。不会,因此我们打印名称并继续进行下一个迭代。

在第三次迭代中,我们<DATA>获得Maria\n,对其进行切分,然后检查哈希键Maria是否存在。它会这样做,因此它将打印与该键关联的值,然后命中last语句。 last通知流控制立即退出封闭循环。循环主块中的其余行将被跳过,并且不再进行迭代。在您的示例代码中,它通常比诸如$var之类的前哨变量更易读,因为代码的阅读者无需跟踪变量可能处于什么状态。

简而言之,您的错误是只从输入文件句柄中读取了一次,然后期望您的循环遇到$name中的更改,尽管它只被分配了一次,然后才进入循环。解决方案是将读取的文件移到循环中。

此模式记录在perldoc perlvar中,我建议您花几分钟阅读一下,以更好地了解该语言。

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

答案 1 :(得分:1)

仅当找到名称时,才重置$ var。

移动此行...

$ var = 0

if / else之后。

您还需要移动此行...

chomp(my $ name =);

在while循环中,在if之前。

答案 2 :(得分:1)

使用此方法,简化了,不需要循环(递归函数):

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

答案 3 :(得分:0)

第20行,“;”丢失

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

简单示例:

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