2009-09-29 4 views
3

У меня есть подпрограмма 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; 
     } 
    } 
} 

Так как рекурсивная подпрограмму в этом?

+4

Почему регресс? Может быть, цикл while? –

+0

Когда я использую some_routine(); для повторного приема ничего не происходит (он не возвращается, попросив пользователя ввести снова для выбора) ... Что мне делать? –

+0

Привет, ВСЕ ... Спасибо за ваши ответы .... Выше моего комментария было из-за одной вещи следующим образом :::::: ==> Когда я даю значение «y» ... $ выбор становится «y \ n», и он не попадает в sttmnt, поскольку он имеет прикрепленный к нему символ новой строки ... Чтобы повторно выполнить подпрограмму в этом случае :: some_routine(); sttmnt достаточно :) –

ответ

2

EDIT: По разным причинам (стиль, производительность и т.д. ...), я бы настоятельно советую не делать рекурсивный вызов здесь, хотя, а проверить его в цикле в то время как.

[Отказ от автоответчика] «С точки зрения стиля, я бы не сделал рекурсивный вызов здесь, но, скорее, проверил его в цикле 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"; 
+1

Производительность? С пользовательским вводом? ROFLAMO! –

7

Там нет причин, чтобы использовать рекурсию для этого. Простой цикл while.

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

Если validate_input возвращает 0, то цикл будет повторяться.

+0

Практически любой (или, вернее, весь) рекурсивный код может быть с разной степенью усилий переписан в виде цикла :) – DVK

10

Для вызова подпрограммы рекурсивно в Perl, просто вызовите к югу от самого себя, так же, как и в любом другом языке:

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

Хотя была и моя первая мысль, но это Perl: есть больше, чем один способ сделать это , –

+2

@Jurily: есть более чем один способ сделать это, но это не значит, что все они одинаково хороши для всех случаев. – Telemachus

+4

* TMTOWTDI, BMOTWAW. * Есть более чем один способ сделать это, но большинство из этих способов ошибочны. –

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

спасибо за редактирование, я не могу поверить, что пропустил их. То, что я получаю за то, что не набрал это в текстовом редакторе выделения. –

4

Правильный способ вызова подпрограммы является

goto &some_routine; 

... потому что у вас есть хвост вызов - это последний что вы делаете в своей функции. Если вы называете это нормально, вы едите кадр стека для каждого вызова, а распределение памяти увеличивается. Вызывается таким образом, вы повторно используете один и тот же стек стека. С вашей точки зрения, как программист, это то же самое, что и

return some_routine(@_); 

но без еды.

только работает для подпрограмм, которые называют их последним, что они делают - в других случаях вы действительно должны переключаться на цикл while, который предлагают другие люди (и, для привлекательности кода, вы можете захотеть сделать это так или иначе).

+3

+1 для хорошего использования goto. –

+0

Здесь нет необходимости. –

+0

Brad: some_routine() был прав, потому что его первоначальный вызов не имеет аргументов. Ваше редактирование (some_routine (@_)) более широко применимо, но на самом деле не требуется здесь. – ijw

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

Гото - хвостовая оптимизация (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; 
    } 
} 

и так ...

+0

Вам не нужно иметь два вызова STDIN. :) –

+0

Скопируйте пасту, и она мне подходит :( –

+0

WAT? - это взлом, чтобы избежать рекурсивных вызовов, перегружающих стек? –

1

Используйте IO::Prompt модуль.

С его помощью вы можете написать это:

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

Ваш вход не эк «у», а «у \ п».

Если вы измените линию на 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; 
     } 
    } 
} 
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; 
} 

Это очень наивный способ, но работает для начинающих.

Смежные вопросы