在Perl中,如何在用户输入无效输入时要求用户重新输入输入?

时间:2009-09-29 06:51:43

标签: perl recursion subroutine

我有一个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;
        }
    }
}

那么如何递归子程序?

9 个答案:

答案 0 :(得分:10)

要在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;
}

答案 1 :(得分:7)

没有理由为此使用递归。一个简单的while循环就可以了。

my $input_valid = 0;
while( !$input_valid ) { 
    print "Enter some input: ";
    my $input = <STDIN>;
    $input_valid = validate_input( $input );
}

如果validate_input返回0,则循环将重复。

答案 2 :(得分:4)

调用例程的正确方法是

goto &some_routine;

...因为你所拥有的是一个尾调用 - 这是你在函数中做的最后一件事。如果你正常调用它,你会为每个调用吃一个堆栈帧,内存分配也会增加。像这样调用,你重复使用相同的堆栈帧。从您作为程序员的角度来看,这与

相同
return some_routine(@_);

但没有吃记忆。

适用于将自己称为他们最后做的事情的例程 - 在其他情况下,您应该切换到其他人建议的while循环(并且,对于代码吸引力,您无论如何都可能想这样做。)

答案 3 :(得分:4)

递归

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;
    }
}

等......

答案 4 :(得分:2)

编辑:由于各种原因(风格,性能等等),我强烈建议不要在这里做一个递归调用,而是检查一下while loop

[Original answerer's disclaimer]“从风格的角度来看,我不会在这里做一个递归调用,而是在一个循环中检查它,但我想在某种程度上,这也是一个品味问题。”

就使用递归而言,作为示例,您可以在函数内调用函数,如下所示:

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";

答案 5 :(得分:2)

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;     
    }
}

答案 6 :(得分:1)

使用IO::Prompt模块。

有了它,你可以这样写:

use IO::Prompt;
my @choices = qw( Apple Mango Grapes );
my $answer = prompt("Select :", "-menu" => \@choices);
print $answer;

答案 7 :(得分:0)

您的输入不是eq“y”而是“y \ n”。

如果您将行更改为if ($choice =~ /^[Yy]/),这将确保您在输入开头捕获Y而不用担心y或是或Y或是。

作为帮助,您应该仅使用<STDIN>而不是STDIN。始终在顶部添加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;
        }
    }
}

答案 8 :(得分:0)

我使用的是一个简单的转到:

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;
}

这是一种非常天真的方式,但适合初学者。