web-dev-qa-db-ja.com

sys.stdin.readline()はプロンプトなしで読み取り、「間に何もない」を返します

私は次のことを実行する関数を持っています(とりわけ):

userinput = stdin.readline()
betAmount = int(userinput)

文字列としてstdinから入力整数を取得し、整数に変換することになっています。

ただし、この関数を呼び出すと、改行文字が1つ返されます(何も入力するのを待ちません)。

プログラムの前半で、次の形式で入力を受け取ります。

stdin.read(1)

単一のキャラクターをキャプチャします。

これには何か関係があるのでしょうか? stdinの次の行にどういうわけか改行文字を書いていますか?

どうすれば修正できますか?

16
lightandlight

stdin.read(1)は、stdinから1文字を読み取ります。その時点で複数の文字が読み込まれた場合(読み込まれた1文字に続く改行など)、その文字は次のread()またはreadline()

例として、与えられた_rd.py_:

_from sys import stdin

x = stdin.read(1)
userinput = stdin.readline()
betAmount = int(userinput)
print ("x=",x)
print ("userinput=",userinput)
print ("betAmount=",betAmount)
_

...このスクリプトを次のように実行した場合(_234_を入力しました):

_C:\>python rd.py
234
x= 2
userinput= 34

betAmount= 34
_

...そのため、最初に_2_がピックアップされ、readline()によって_34_と末尾の改行文字がピックアップされます。

ほとんどの場合、readline()ではなくread()を使用して問題を解決することをお勧めします。

22
Simon

Simonの答えとVolcanoがあなたの間違ったことを説明し、Simonがインターフェイスを再設計することでそれを修正する方法を説明します。

しかし、実際に1文字を読み、その後1行を読む必要がある場合、それを行うことができます。それは些細なことではなく、Windowsと他のすべてで異なります。

実際には3つのケースがあります:Unix tty、Windows DOSプロンプト、またはいずれかのプラットフォーム上の通常ファイル(リダイレクトされたファイル/パイプ)。そして、それらを異なる方法で処理する必要があります。

最初に、stdinがtty(WindowsとUnixの両方の種類)かどうかを確認するには、sys.stdin.isatty()を呼び出すだけです。その部分はクロスプラットフォームです。

Tty以外の場合は、簡単です。実際にはうまくいくかもしれません。そうでない場合は、_sys.stdin_の下にあるバッファされていないオブジェクトから読み取ることができます。 Python 3)では、これは単にsys.stdin.buffer.raw.read(1)sys.stdin.buffer.raw.readline()を意味します。ただし、これは文字列ではなくエンコードされたバイトを取得するため、結果に対して.decode(sys.stdin.decoding)を呼び出します;それをすべて関数にまとめることができます。

ただし、Windowsのttyケースの場合、入力は未加工のバッファーでも行バッファーされます。これを回避する唯一の方法は、通常のファイルI/Oの代わりに Console I/O 関数を使用することです。したがって、stdin.read(1)の代わりに、msvcrt.getwch()を実行します。

Unixのttyの場合、端末を通常の回線制御モードではなくrawモードに設定する必要があります。これを行うと、同じsys.stdin.buffer.read(1)などを使用できますが、それは機能します。 (スクリプトの最後まで)永続的にそれを実行したい場合は、 _tty.setraw_ 関数を使用すると簡単です。後でラインディシプリンモードに戻りたい場合は、 termios モジュールを使用する必要があります。これは恐ろしいように見えますが、setrawを呼び出す前にtermios.tcgetattr(sys.stdin.fileno())の結果を隠しておけばtermios.tcsetattr(sys.stdin.fileno(), TCSAFLUSH, stash)を実行すれば、それらすべての厄介なビットを学ぶ必要はありません。平均。

両方のプラットフォームで、コンソールI/Oとrawターミナルモードの混在は苦痛です。コンソール/生の読み取りを行ったことがある場合は、_sys.stdin_バッファーを絶対に使用できません。 _sys.stdin.buffer.raw_のみを使用できます。改行を取得するまでreadlineを1文字ずつ読み取ることでいつでも置き換えることができますが、ユーザーがバックスペース、矢印、emacsスタイルのコマンドキーなどを使用してエントリを編集しようとすると、これらすべてを、扱いたくない生のキー押下として取得します。

11
abarnert
stdin.read(1)

1文字を押しても戻りません-'\ n'を待ちます。問題は、2番目の文字が標準入力でバッファリングされ、別の入力を呼び出した瞬間です。バッファから入力を取得するため、すぐに戻ります。

3
volcano

必要な文字が1つだけで、バッファに物を残したくない場合は、行全体を読み、不要なものをすべてドロップできます。

交換:

stdin.read(1)

stdin.readline().strip()[:1]

これにより、行が読み取られ、スペースと改行が削除され、最初の文字だけが保持されます。

2
ale5000

これを試して ...

import sys
buffer = []
while True:
    userinput = sys.stdin.readline().rstrip('\n')
    if userinput == 'quit':
        break
    else:
        buffer.append(userinput)
0
Reuben