2011-11-08 16 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