fscanf
またはJavaに相当するものはありませんScanner
。最も簡単な解決策は、スペースで区切られた入力の代わりに改行で区切られた入力を使用するようにユーザーに要求することです。その後、行ごとに読み取り、行を正しいタイプに変換できます。
ユーザーがより構造化された入力を提供できるようにする場合は、ユーザー入力用のパーサーを作成する必要があります。pyparsingなど、Python用の優れた解析ライブラリがいくつかあります。scanf
最終更新は2008年ですが、モジュールもあります。
外部依存関係が必要ない場合は、正規表現を使用して入力シーケンスを照合できます。確かに正規表現は文字列を処理する必要がありますが、チャンクで読み取るというこの制限を簡単に克服できます。たとえば、このようなものはほとんどの場合うまくいくはずです:
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
おそらくこれを拡張して適切にテストする必要がありますが、いくつかのアイデアが得られるはずです。