2011-11-08 17 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、選択したものが期待どおりに動作します。何か他のものを入力すると(elseブロックをトリガーするために)、ReadKey()が入力を受け入れる前にループが3回または4回反復します。ベストこの出力によって示される(私はXXXを入力した後、「選択:>」私はYYYを入力することができたの前に3回印刷):

$ ./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は一度に1回ずつ各キーストロークを返すようになります。

解決方法は、探している動作によって異なります。 を押す必要がある場合入力に作用する前にと入力すると、一度に1行ずつ読むことができます(標準<>演算子)。 Term::ReadKeyはまったく必要ありません。

キーを押した直後にアクションを実行する場合は、Term::ReadKeyReadMode機能を使用して入力バッファリングを変更する必要があります。プログラムの終了時に元のモードに戻すには、END { ReadMode(0) }を追加することを忘れないでください。

+0

ダー。 "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を使用して1ヶ月です、それは...クリーナーコードのおかげで示しています。私は 'say 'が何をするのか、この正規表現が'/^ \ d + $/'を意味するのかを把握するためにgoogleを使わなければなりません。ありがとう! –

+0

ニート私はGoogleが大好きです。私はb/cと言うことはできません。私はperl 5.8に固執していますが、印刷は十分に機能します。 \ dは数字にマッチします。もちろん。私は今、よりスマートに感じます。 :-) –

+0

'perldoc -f say'、' perldoc perlre'はあなたのコマンドプロンプトで正しいです。また、このドキュメントは[perldoc.perl.org](http://perldoc.perl.org)の 'say'の最後に改行を入れて表示するだけです。 '/^\ d + $ /'は、文字列の開始、\ d桁、1回以上のマッチ、行末$を意味します。つまり、**文字列に**数字だけがあるかどうかをチェックします。 – TLP

関連する問題