Non vi è alcun equivalente di fscanf
o Java Scanner
. La soluzione più semplice è quella di richiedere all'utente di utilizzare l'input separato newline anziché l'input separato dallo spazio, quindi è possibile leggere riga per riga e convertire le righe nel tipo corretto.
Se si desidera che l'utente fornisca un input più strutturato, è consigliabile creare un parser per l'input dell'utente. Esistono alcune librerie di analisi per Python, ad esempio pyparsing. Esiste anche un modulo scanf
, anche se l'ultimo aggiornamento è del 2008.
Se non si desidera avere dipendenze esterne, è possibile utilizzare espressioni regex per far corrispondere le sequenze di input. Certamente le regex richiedono di lavorare su stringhe, ma puoi facilmente superare questa limitazione leggendo in blocchi. Per esempio qualcosa come questo dovrebbe funzionare bene la maggior parte del tempo:
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 ''
Esempio di utilizzo:
>>> 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
Probabilmente dovrete estendere questo, e testare in modo corretto ma dovrebbe darvi alcune idee .
Se l'input è molto sporco/arbitrario, tendo ad usare il modulo 're'; se l'input è strutturato preferisco una libreria parser come simpleparse (EBNL è più semplice da gestire rispetto alle espressioni regolari). –
Se hai in mente un caso d'uso, forse sarebbe più produttivo aggiornare la tua domanda invece di fare un'inchiesta generica. –
Vedere http://stackoverflow.com/questions/2175080/sscanf-in-python per altri suggerimenti. –