簡體   English   中英

perl-使用ReadKey的怪異循環行為

[英]perl - weird loop behavior with ReadKey

出於某種原因,在我的簡單菜單程序中,由於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塊),則循環將重復3或4次,直到ReadKey()再次接受輸入。 最好用此輸出說明(我輸入xxx,然后在輸入yyy之前打印了3次“ Selection:>”):

$ ./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

這是因為ReadKey讀取密鑰 當您按x 3次,然后按Enter時 ,這是4個鍵。 實際上,即使是正確的選擇( 1 Enter )也有2個鍵。 您只是沒有注意到,因為您的程序會立即退出。

這不太明顯,因為默認輸入模式會緩沖擊鍵,直到您按Enter鍵為止。 屆時, ReadKey將開始一次返回每個擊鍵。

解決方案取決於您要尋找的行為。 如果要在對輸入進行操作之前必須先按Enter鍵 ,則可以一次讀取一行(使用標准<>運算符)。 您根本不需要Term::ReadKey

如果要在按鍵后立即采取措施,則需要使用Term::ReadKeyReadMode函數來更改輸入緩沖。 程序退出時,請不要忘記添加END { ReadMode(0) }以恢復原始模式。

看起來您的程序讀取了一個鍵,進入else循環並在您鍵入其他字符時進入睡眠狀態,然后繼續。 您可能正遭受緩沖的困擾,因為在使用睡眠時不會立即進行打印。

您的程序可以使用一些替代方法。 這是一個例子:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM