3

ユーザーからの入力を求める 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;
        }
    }
}

では、これでサブルーチンを再帰する方法は?

4

9 に答える 9

10

To call a subroutine recursively in Perl, you just call the sub from itself, the same as in any other language:

sub factorial {
  my $num = shift;
  return 1 if $num < 2;
  return $num * factorial($num - 1);
}

However, you don't really want to use recursion for a "repeat until condition changes" scenario.
That's what while loops are for
:

my $valid;
while (!$valid) {
  print "Enter something: ";
  my $data = <STDIN>;
  $valid = validate($data);
  print "Bzzt!  Invalid - try again!\n" unless $valid;
}
于 2009-09-29T07:04:16.130 に答える
7

There's no reason to use recursion for this. A simple while loop will do.

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

If validate_input returns 0, the loop will repeat.

于 2009-09-29T07:03:55.437 に答える
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;
    }
}

など ...

于 2009-09-29T10:50:45.970 に答える
4

ルーチンを呼び出す正しい方法は次のとおりです。

goto &some_routine;

...あなたが持っているのは末尾呼び出しだからです-それはあなたがあなたの関数で行う最後のことです。通常どおりに呼び出すと、呼び出しごとにスタックフレームが使用され、メモリ割り当てが増加します。このように呼ばれ、同じスタックフレームを再利用します。プログラマーとしてのあなたの観点から、これはと同じです

return some_routine(@_);

しかし、記憶を食べずに。

これは、自分自身を最後に呼び出すルーチンでのみ機能します。他の場合は、他の人が提案するwhileループに切り替える必要があります(コードの魅力のために、とにかくそれを実行することをお勧めします)。

于 2009-09-29T08:44:51.230 に答える
2

EDIT: For a variety of reasons (style, performance, etc...), I would strongly advise not do a recursive call here, though, but rather check it in a while loop.

[Original answerer's disclaimer] "From a style perspective, I would not do a recursive call here, though, but rather check it in a while loop, but I guess to a degree, that's a matter of taste as well."

As far as using recursion, as an example, you can just call the function from within the function, like so:

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";
于 2009-09-29T07:03:54.477 に答える
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;     
    }
}
于 2009-09-29T08:05:59.657 に答える
1

IO::Promptモジュールを使用します。

それを使用すると、次のように記述できます。

use IO::Prompt;
my @choices = qw( Apple Mango Grapes );
my $answer = prompt("Select :", "-menu" => \@choices);
print $answer;
于 2009-09-30T05:27:28.580 に答える
0

あなたの入力は eq "y" ではなく "y\n" です。

行をif ($choice =~ /^[Yy]/)これに変更すると、入力の先頭で Y を確実にキャッチし、y または yes または Y または Yes を心配する必要がなくなります。

ヘルプとして、単独では<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;
        }
    }
}
于 2009-10-01T13:25:31.403 に答える
0

私が使用するのは単純なgotoです:

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

これは非常に素朴な方法ですが、初心者向けです。

于 2010-12-01T19:24:54.167 に答える