5

多くのプログラミング言語の標準ライブラリには、テキスト入力ストリームから文字列、数値、またはその他のオブジェクトを抽出するための「スキャナー API」が含まれています。(たとえば、Java にはScannerクラスが含まれ、C++ には が含まれistream、C には含まれますscanf)。

Pythonでこれに相当するものは何ですか?

Python にはストリーム インターフェイス、つまり を継承するクラスがありますio.IOBase。ただし、PythonTextIOBaseストリーム インターフェイスは、行指向の入力用の機能のみを提供します。ドキュメントを読んで Google で検索した後、たとえば、テキスト ストリームから整数を抽出したり、スペースで区切られた次の単語を文字列として抽出したりできる標準の Python モジュールが見つかりません。これを行うための標準的な機能はありますか?

4

2 に答える 2

3

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

おそらくこれを拡張して適切にテストする必要がありますが、いくつかのアイデアが得られるはずです。

于 2013-02-16T08:58:01.257 に答える
1

直接同等のものはありません(私の知る限り)。しかし、正規表現でもほぼ同じことができます (reモジュールを参照)。

例えば:

# matching first integer (space delimited)
re.match(r'\b(\d+)\b',string)

# matching first space delimited word
re.match(r'\b(\w+)\b',string)

# matching a word followed by an integer (space delimited)
re.match(r'\b(\w+)\s+(\d+)\b',string)

通常の C スタイルのスキャナ インターフェイスよりも少し手間がかかりますが、非常に柔軟で強力です。ただし、ストリーム I/O を自分で処理する必要があります。

于 2013-02-16T01:28:29.550 に答える