[英]How can I ask the user to re-enter input when they enter invalid input, in Perl?
我有一个Perl子程序,它要求用户输入。 无论输入的输入是否为有效输入,我都会在子程序内部执行检查。
如果不是,我想再次调用子程序让用户输入有效输入。
我的子程序如下:
sub some_routine {
print "Enter a number to select (1) Apple (2) Mango (3) grapes:"
$value=STDIN;
if($value =~ /[^1-3]/ ) {
print "The input is not valid!";
print "Do you want to continue selecting a fruit again (Y or N)?";
$choice = STDIN;
if( $choice eq "y") {
### I want to call the subroutine again to enter input ###
} else {
exit;
}
}
}
那么如何递归子程序呢?
要在Perl中递归调用子例程,只需从自身调用sub,就像在任何其他语言中一样:
sub factorial {
my $num = shift;
return 1 if $num < 2;
return $num * factorial($num - 1);
}
但是,您实际上并不想使用递归来“重复直到条件更改”方案。
那就是while
循环用于 :
my $valid;
while (!$valid) {
print "Enter something: ";
my $data = <STDIN>;
$valid = validate($data);
print "Bzzt! Invalid - try again!\n" unless $valid;
}
这没有理由使用递归。 一个简单的while
循环就行了。
my $input_valid = 0;
while( !$input_valid ) {
print "Enter some input: ";
my $input = <STDIN>;
$input_valid = validate_input( $input );
}
如果validate_input
返回0,则循环将重复。
调用例程的正确方法是
goto &some_routine;
...因为你拥有的是一个尾调用 - 这是你在函数中做的最后一件事。 如果你正常调用它,你会为每个调用吃一个堆栈帧,内存分配也会增加。 像这样调用,你重复使用相同的堆栈帧。 从你作为程序员的角度来看,这是一样的
return some_routine(@_);
但没有吃记忆。
这仅适用于将自己称为最后一件事的例程 - 在其他情况下,您应该切换到其他人建议的while循环(并且,对于代码吸引力,您可能仍然想要这样做)。
递归
sub select_fruit {
print "Enter a number to select (1) Apple (2) Mango (3) grapes:"
$value=<STDIN>;
if($value =~ /[^1-3]/ ) {
print "The input is not valid!";
print "Do you want to continue selecting a fruit again (Y or N)?";
$choice = <STDIN>;
if( $choice eq "y") {
$value = select_fruit();
} else {
exit;
}
}
return $value;
}
goto - 尾部呼叫优化(TCO)
sub select_fruit {
print "Enter a number to select (1) Apple (2) Mango (3) grapes:"
$value=<STDIN>;
if($value =~ /[^1-3]/ ) {
print "The input is not valid!";
print "Do you want to continue selecting a fruit again (Y or N)?";
$choice = <STDIN>;
if( $choice eq "y") {
goto &select_fruit;
} else {
exit;
}
}
return $value;
}
或重做
sub select_fruit {
SELECT_FRUIT: {
print "Enter a number to select (1) Apple (2) Mango (3) grapes:"
$value=<STDIN>;
if($value =~ /[^1-3]/ ) {
print "The input is not valid!";
print "Do you want to continue selecting a fruit again (Y or N)?";
$choice = <STDIN>;
if( $choice eq "y") {
redo SELECT_FRUIT; # same as goto SELECT_FRUIT;
} else {
exit;
}
}
return $value;
}
}
所以 ...
编辑:由于各种原因(风格,性能等...), 我强烈建议不要在这里做一个递归调用,而是在while循环中检查它 。
[原始回答者的免责声明]“从风格的角度来看,我不会在这里进行递归调用,而是在一段时间内检查它,但我想在某种程度上,这也是一种品味问题。”
至于使用递归,作为一个例子,你可以从函数内部调用函数,如下所示:
sub get_positive_number {
print "Please enter a positive number: ";
my $number = <STDIN>;
chomp $number;
if ($number > 0) {
return $number;
}
else {
return get_positive_number();
}
}
my $result = get_positive_number();
print "result: $result\n";
my $value;
until(defined $value = get_value()) {
print"you didn't enter a valid value\n";
}
sub get_value {
print "Enter a number to select (1) Apple (2) Mango (3) grapes:"
$value=<STDIN>;
if($value =~ /[1-3]/ ) {
return $value;
} else {
return undef;
}
}
使用IO :: Prompt模块。
有了它,你可以像这样写:
use IO::Prompt;
my @choices = qw( Apple Mango Grapes );
my $answer = prompt("Select :", "-menu" => \@choices);
print $answer;
您的输入不是eq“y”而是“y \\ n”。
如果你将行更改为if ($choice =~ /^[Yy]/)
这将确保你在输入开始时捕获Y而不用担心y或yes或Y或Yes。
作为帮助,您应该单独使用<STDIN>
而不是STDIN
。 始终加use strict; use warnings;
use strict; use warnings;
在顶部。 这确保您需要使用以下内容定义$ value和$ choice:
my $value = '';
my $choice = '';
正如其他人提到的那样。 这可能比循环更简单。
#!/usr/bin/env perl
use strict;
use warnings;
some_routine();
sub some_routine {
my $value = '';
my $choice = '';
print "Enter a number to select (1) Apple (2) Mango (3) grapes:";
$value = <STDIN>;
if($value !~ /[1-3]/ ) {
print "The input is not valid!";
print "Do you want to continue selecting a fruit again (Y or N)?";
$choice = <STDIN>;
if( $choice =~ /[Yy]/) {
some_routine();
} else {
exit;
}
}
}
我用的是一个简单的转到:
START:
print "\n Name of the country (any one out of: china, japan or tokyo): ";
my $country_name = <>;
chomp($country_name);
unless ($country_name eq "china" || $country_name eq "japan" ||
$country_name eq "tokyo") {
print "\n Invalid country name entered. Please try again. \n";
goto START;
}
这是一种非常天真的方式,但适合初学者。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.