Pythonでsscanf()
に相当するものを探しています。 /proc/net/*
ファイルを解析したいので、Cでは次のようなことができます。
int matches = sscanf(
buffer,
"%*d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %*X %*X:%*X %*X:%*X %*X %*d %*d %ld %*512s\n",
local_addr, &local_port, rem_addr, &rem_port, &inode);
最初はstr.split
を使用することを考えましたが、指定された文字では分割されませんが、sep
文字列全体は分割されます。
>>> lines = open("/proc/net/dev").readlines()
>>> for l in lines[2:]:
>>> cols = l.split(string.whitespace + ":")
>>> print len(cols)
1
上で説明したように、17を返すはずです。
Python sscanf
(REではない)に相当)、または標準ライブラリに文字列分割関数がありますが、これは知らない文字の範囲で分割しますの?
Pythonにはsscanf
に相当する組み込み機能がありません。ほとんどの場合、文字列を直接操作したり、正規表現を使用したり、解析ツールを使用して入力を解析する方がはるかに理にかなっています。
おそらくCの翻訳に最も役立つでしょう。人々はこのモジュールのようにsscanf
を実装しています: http://hkn.eecs.berkeley.edu/~dyoo/python/scanf/
この特定のケースでは、複数の分割文字に基づいてデータを分割する場合は、re.split
は本当に正しいツールです。
parse
モジュールもあります。
parse()
は、format()
(Python 2.6以降)の新しい文字列フォーマット関数)の反対になるように設計されています。
>>> from parse import parse
>>> parse('{} fish', '1')
>>> parse('{} fish', '1 fish')
<Result ('1',) {}>
>>> parse('{} fish', '2 fish')
<Result ('2',) {}>
>>> parse('{} fish', 'red fish')
<Result ('red',) {}>
>>> parse('{} fish', 'blue fish')
<Result ('blue',) {}>
私がCムードにあるとき、私は通常、scanfのような振る舞いのためにZipとリストの内包表記を使用します。このような:
input = '1 3.0 false hello'
(a, b, c, d) = [t(s) for t,s in Zip((int,float,strtobool,str),input.split())]
print (a, b, c, d)
より複雑なフォーマット文字列には、正規表現を使用する必要があることに注意してください。
import re
input = '1:3.0 false,hello'
(a, b, c, d) = [t(s) for t,s in Zip((int,float,strtobool,str),re.search('^(\d+):([\d.]+) (\w+),(\w+)$',input).groups())]
print (a, b, c, d)
また、変換するすべてのタイプの変換関数が必要であることに注意してください。たとえば、上記のようなものを使用しました:
strtobool = lambda s: {'true': True, 'false': False}[s]
re
モジュールを使用して、文字の範囲で分割できます。
>>> import re
>>> r = re.compile('[ \t\n\r:]+')
>>> r.split("abc:def ghi")
['abc', 'def', 'ghi']
名前付きグループ を使用して、モジュールre
で解析できます。部分文字列を実際のデータ型(たとえば、int
)に解析しませんが、文字列を解析するときに非常に便利です。
このサンプル行が/proc/net/tcp
:
line=" 0: 00000000:0203 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 335 1 c1674320 300 0 0 0"
変数を使用してsscanfの例を模倣する例は次のとおりです。
import re
hex_digit_pattern = r"[\dA-Fa-f]"
pat = r"\d+: " + \
r"(?P<local_addr>HEX+):(?P<local_port>HEX+) " + \
r"(?P<rem_addr>HEX+):(?P<rem_port>HEX+) " + \
r"HEX+ HEX+:HEX+ HEX+:HEX+ HEX+ +\d+ +\d+ " + \
r"(?P<inode>\d+)"
pat = pat.replace("HEX", hex_digit_pattern)
values = re.search(pat, line).groupdict()
import pprint; pprint values
# prints:
# {'inode': '335',
# 'local_addr': '00000000',
# 'local_port': '0203',
# 'rem_addr': '00000000',
# 'rem_port': '0000'}
基本的なscanfを実装するActiveStateレシピがあります http://code.activestate.com/recipes/502213-simple-scanf-implementation/
更新:正規表現モジュールre
のPythonドキュメント)には、scanfのシミュレーションに関するセクションが含まれています。
投票したoripの答え。 reモジュールを使用するのは適切なアドバイスだと思います。 Kodosアプリケーションは、Pythonで複雑な正規表現タスクにアプローチするときに役立ちます。
「:」をスペースに変えて、split.egを実行できます。
>>> f=open("/proc/net/dev")
>>> for line in f:
... line=line.replace(":"," ").split()
... print len(line)
正規表現は必要ありません(この場合)
区切り文字が「:」の場合、「:」で分割し、文字列でx.strip()を使用して、先頭または末尾の空白を削除できます。 int()はスペースを無視します。
odiakによるPython 2実装 があります。