from itertools import chain, repeat
prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number: a
Not a number! Try again: b
Not a number! Try again: 1
1
または、他の回答のように、「不正な入力」メッセージを入力プロンプトから分離したい場合:
prompt_msg = "Enter a number: "
bad_input_msg = "Sorry, I didn't understand that."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number: a
Sorry, I didn't understand that.
Enter a number: b
Sorry, I didn't understand that.
Enter a number: 1
1
どのように機能しますか?
prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
とのこの組み合わせはitertools.chain
、itertools.repeat
文字列を"Enter a number: "
1回、"Not a number! Try again: "
無限回数生成するイテレータを作成します。
for prompt in prompts:
print(prompt)
Enter a number:
Not a number! Try again:
Not a number! Try again:
Not a number! Try again:
# ... and so on
replies = map(input, prompts)
-ここでmap
はprompts
、前のステップのすべての文字列をinput
関数に適用します。例えば:
for reply in replies:
print(reply)
Enter a number: a
a
Not a number! Try again: 1
1
Not a number! Try again: it doesn't care now
it doesn't care now
# and so on...
- とを使用して
filter
、str.isdigit
数字のみを含む文字列を除外します。
only_digits = filter(str.isdigit, replies)
for reply in only_digits:
print(reply)
Enter a number: a
Not a number! Try again: 1
1
Not a number! Try again: 2
2
Not a number! Try again: b
Not a number! Try again: # and so on...
そして、最初の数字のみの文字列のみを取得するために使用しますnext
。
その他の検証ルール:
文字列メソッド:もちろん、他の文字列メソッドを使用してstr.isalpha
、アルファベット文字列str.isupper
のみを取得したり、大文字のみを取得したりできます。完全なリストについては、ドキュメントを参照してください。
メンバーシップテスト:
実行するにはいくつかの方法があります。それらの1つは__contains__
メソッドを使用することです。
from itertools import chain, repeat
fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
valid_response = next(filter(fruits.__contains__, replies))
print(valid_response)
Enter a fruit: 1
I don't know this one! Try again: foo
I don't know this one! Try again: apple
apple
数値比較:
ここで使用できる便利な比較方法があります。たとえば、__lt__
(<
)の場合:
from itertools import chain, repeat
prompts = chain(["Enter a positive number:"], repeat("I need a positive number! Try again:"))
replies = map(input, prompts)
numeric_strings = filter(str.isnumeric, replies)
numbers = map(float, numeric_strings)
is_positive = (0.).__lt__
valid_response = next(filter(is_positive, numbers))
print(valid_response)
Enter a positive number: a
I need a positive number! Try again: -5
I need a positive number! Try again: 0
I need a positive number! Try again: 5
5.0
または、dunderメソッド(dunder = double-underscore)を使用したくない場合は、いつでも独自の関数を定義するか、operator
モジュールの関数を使用できます。
パスの存在:
ここでは、pathlib
ライブラリとそのPath.exists
メソッドを使用できます。
from itertools import chain, repeat
from pathlib import Path
prompts = chain(["Enter a path: "], repeat("This path doesn't exist! Try again: "))
replies = map(input, prompts)
paths = map(Path, replies)
valid_response = next(filter(Path.exists, paths))
print(valid_response)
Enter a path: a b c
This path doesn't exist! Try again: 1
This path doesn't exist! Try again: existing_file.txt
existing_file.txt
試行回数の制限:
無限に何かを尋ねることでユーザーを拷問したくない場合は、の呼び出しで制限を指定できますitertools.repeat
。これは、next
関数にデフォルト値を提供することと組み合わせることができます。
from itertools import chain, repeat
prompts = chain(["Enter a number:"], repeat("Not a number! Try again:", 2))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies), None)
print("You've failed miserably!" if valid_response is None else 'Well done!')
Enter a number: a
Not a number! Try again: b
Not a number! Try again: c
You've failed miserably!
入力データの前処理:
ユーザーが誤って提供されている場合時々 、入力を拒否したくないCAPS INまたは文字列の先頭または末尾にスペースを。これらの単純な間違いを考慮に入れるためにstr.lower
、str.strip
メソッドとメソッドを適用して入力データを前処理できます。たとえば、メンバーシップテストの場合、コードは次のようになります。
from itertools import chain, repeat
fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
lowercased_replies = map(str.lower, replies)
stripped_replies = map(str.strip, lowercased_replies)
valid_response = next(filter(fruits.__contains__, stripped_replies))
print(valid_response)
Enter a fruit: duck
I don't know this one! Try again: Orange
orange
前処理に使用する関数が多い場合は、関数合成を行う関数を使用した方が簡単な場合があります。たとえば、ここからのものを使用します:
from itertools import chain, repeat
from lz.functional import compose
fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
process = compose(str.strip, str.lower) # you can add more functions here
processed_replies = map(process, replies)
valid_response = next(filter(fruits.__contains__, processed_replies))
print(valid_response)
Enter a fruit: potato
I don't know this one! Try again: PEACH
peach
検証ルールを組み合わせる:
単純なケースでは、たとえば、プログラムが1から120までの年齢を要求する場合、別の年齢を追加できますfilter
。
from itertools import chain, repeat
prompt_msg = "Enter your age (1-120): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
numeric_replies = filter(str.isdigit, replies)
ages = map(int, numeric_replies)
positive_ages = filter((0).__lt__, ages)
not_too_big_ages = filter((120).__ge__, positive_ages)
valid_response = next(not_too_big_ages)
print(valid_response)
ただし、多くのルールがある場合は、論理結合を実行する関数を実装することをお勧めします。次の例では、ここから既製のものを使用します。
from functools import partial
from itertools import chain, repeat
from lz.logical import conjoin
def is_one_letter(string: str) -> bool:
return len(string) == 1
rules = [str.isalpha, str.isupper, is_one_letter, 'C'.__le__, 'P'.__ge__]
prompt_msg = "Enter a letter (C-P): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(conjoin(*rules), replies))
print(valid_response)
Enter a letter (C-P): 5
Wrong input.
Enter a letter (C-P): f
Wrong input.
Enter a letter (C-P): CDE
Wrong input.
Enter a letter (C-P): Q
Wrong input.
Enter a letter (C-P): N
N
残念ながら、失敗したケースごとにカスタムメッセージが必要な場合は、残念ながら、かなり機能的な方法はありません。または、少なくとも、私はそれを見つけることができませんでした。