fscanf
またはJavaのScanner
に相当するものはありません。一番簡単な解決策は、スペース区切りの入力の代わりに改行入力を使用するようにユーザーに要求することです。その後、行単位で読み込み、行を正しい型に変換することができます。
ユーザーがより構造化された入力を提供したい場合は、おそらくユーザー入力用のパーサーを作成する必要があります。 Python用のいくつかの素晴らしい構文解析ライブラリがあります。たとえば、pyparsingです。最後の更新が2008年であっても、scanf
モジュールがあります。
外部依存関係が必要ない場合は、正規表現を使用して入力シーケンスを一致させることができます。確かに正規表現は文字列で作業する必要がありますが、チャンクで読むこの制限を簡単に克服できます。例えば、このような何かがうまくほとんどの時間を動作するはずです:
import re
FORMATS_TYPES = {
'd': int,
'f': float,
's': str,
}
FORMATS_REGEXES = {
'd': re.compile(r'(?:\s|\b)*([+-]?\d+)(?:\s|\b)*'),
'f': re.compile(r'(?:\s|\b)*([+-]?\d+\.?\d*)(?:\s|\b)*'),
's': re.compile(r'\b(\w+)\b'),
}
FORMAT_FIELD_REGEX = re.compile(r'%(s|d|f)')
def scan_input(format_string, stream, max_size=float('+inf'), chunk_size=1024):
"""Scan an input stream and retrieve formatted input."""
chunk = ''
format_fields = format_string.split()[::-1]
while format_fields:
fields = FORMAT_FIELD_REGEX.findall(format_fields.pop())
if not chunk:
chunk = _get_chunk(stream, chunk_size)
for field in fields:
field_regex = FORMATS_REGEXES[field]
match = field_regex.search(chunk)
length_before = len(chunk)
while match is None or match.end() >= len(chunk):
chunk += _get_chunk(stream, chunk_size)
if not chunk or length_before == len(chunk):
if match is None:
raise ValueError('Missing fields.')
break
text = match.group(1)
yield FORMATS_TYPES[field](text)
chunk = chunk[match.end():]
def _get_chunk(stream, chunk_size):
try:
return stream.read(chunk_size)
except EOFError:
return ''
使用例:
>>> s = StringIO('1234 Hello World -13.48 -678 12.45')
>>> for data in scan_input('%d %s %s %f %d %f', s): print repr(data)
...
1234
'Hello'
'World'
-13.48
-678
12.45
あなたはおそらくこれを拡張し、適切にそれをテストする必要がありますが、それはあなたにいくつかのアイデアを与える必要があります。
入力が非常に汚い/任意の場合、私は 're'モジュールを使用する傾向があります。入力が構造化されているなら、私はsimpleparse(EBNLは正規表現よりも保守が容易です)のようなパーサーライブラリを好むでしょう。 –
ユースケースを念頭に置いている場合は、一般的なお問い合わせを行う代わりに、質問を更新する方がより生産的になる可能性があります。 –
他の提案についてはhttp://stackoverflow.com/questions/2175080/sscanf-in-pythonを参照してください。 –