2011-11-08 14 views
1

出于某种原因,奇怪的循环行为,我简单的菜单程序,奇怪的事情发生,因为ReadKey的结果()perl的 - 与ReadKey

#!/usr/local/bin/perl 

use strict ; 
use warnings ; 
use English ; 
use Term::ReadKey ; 

my @available_choices = ('choice one', 'choice two', 'choice three') ; 
my $array_size = scalar (@available_choices) ; 

print "\nPlease make your selection from the options below:\n\n" ; 

for (my $i=0, my $j=1 ; $i < $array_size ; $i++, $j++) { 
    print "$j) $available_choices[$i]\n" ; 
} 

my $key = undef ; 
for (my $k=0; $k < 5; $k++) { 
    print "\nSelection :> " ; 
    $key = ReadKey(); 
    if ((defined $key) && ($key =~ /[1-$array_size]/)) { 
    print "\nYou selected \"$available_choices[$key-1]\"\n" ; 
    last ; 
    } 
    else { 
    sleep 1 ; 
    } 
} 

所以,如果你运行这个简单的程序,并给予1,2,或3作为您的选择它按预期工作。如果你输入了其他东西(来触发else块),那么在ReadKey()再次接受输入之前,循环重复3或4次。这个输出最好的说明(我进入XXX,然后在“选择:>”印刷3次,我能键入YYY前):

$ ./bar.pl 

Please make your selection from the options below: 

1) choice one 
2) choice two 
3) choice three 

Selection :> xxx 

Selection :> 
Selection :> 
Selection :> 
Selection :> yyy 

回答

4

这是因为ReadKey读取关键。当您按x 3次然后输入,即4键。事实上,即使是正确的选择( 输入)是2个键;你只是没有注意到,因为你的程序立即退出。

这是不明显的,因为默认输入模式缓冲击键直到您按输入。此时,ReadKey将开始每次返回一个按键。

解决方案取决于您要查找的行为。如果您想在输入之前按输入,那么您可以一次只读一行(使用标准<>运算符)。根本不需要Term::ReadKey

如果您想在按键后立即采取措施,您需要使用Term::ReadKeyReadMode函数来更改输入缓冲。当您的程序退出时,请不要忘记添加END { ReadMode(0) }以恢复原始模式。

+0

Duh。 “ReadKey读取_key_”说明了一切。谢谢! –

1

看起来你的程序读取钥匙,进入别人循环,睡觉当你键入你的其他角色,然后继续。使用睡眠时,您可能会因缓冲而不能立即发生打印。

您的程序可以使用一些替代方法。这里有一个例子:

use strict; 
use warnings; 
use v5.10; 

my @available_choices = ('choice one', 'choice two', 'choice three') ; 

print "\nPlease make your selection from the options below:\n\n" ; 

# Using a block to reduce scope of $i 
# No need to use a separate variable for the array length 
{ 
    my $i = 0; 
    say ++$i, ") $_" for @available_choices; 
} 

# No need to use a temp variable for a loop 
# Also, might be better off with an infinite loop, 
# rather than one with 5 cycles. 

#for (0 .. 4) { 
while (1) { 
    print "\nSelection :> " ; 
    chomp(my $key = <>);  # Using STDIN instead of ReadKey 
    last if $key =~ /^q$/i; # easy exit 
    next unless $key =~ /^\d+$/; 
    if (defined $available_choices[$key-1]) { 
     say qq(\nYou selected "$available_choices[$key-1]"\n); 
     last; 
    } 
} 
+0

那么,我使用Perl一个月,它显示...感谢更清晰的代码。我必须谷歌找出'说'做什么,这个正则表达式意味着'/^\ d + $ /'。谢谢! –

+0

整洁。我爱谷歌。我不能用说b/c我困在perl 5.8,但打印效果不错。 \ d匹配数字。当然。我现在感觉更聪明了。 :-) –

+0

'perldoc -f say','perldoc perlre'就在您的命令提示符下。你也可以在[perldoc.perl.org](http://perldoc.perl.org)找到这个文档,'say'只是在最后打印一个换行符。 '/^\ d + $ /'表示:^字符串开头,\ d数字,+匹配一次或多次,$行尾。换句话说,它检查字符串中是否只有**数字。 – TLP