sscanf在Python中
我正在寻找一个相当于Python中的sscanf()
。 我想parsing/proc/net/*
文件,在CI可以做这样的事情:
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
string:
>>> lines = open("/proc/net/dev").readlines() >>> for l in lines[2:]: >>> cols = l.split(string.whitespace + ":") >>> print len(cols) 1
如上所述,应该返回17。
是否有一个相当于sscanf
的Python(不是RE),还是标准库中的一个string分割函数,它在我不知道的任何字符范围内进行分割?
Python没有与sscanf
等效的内置function,而且大多数情况下,通过直接使用string,使用正则expression式或使用parsing工具来parsinginput,大部分时间是更合理的。
可能主要用于翻译C,人们已经实现了sscanf
,比如在这个模块中: http : //hkn.eecs.berkeley.edu/~dyoo/python/scanf/
在这种特殊情况下,如果您只是想根据多个拆分字符拆分数据, re.split
确实是一个正确的工具。
当我处于C心情时,我通常使用zip和列表parsing来实现类似于scanf的行为。 喜欢这个:
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)
请注意,对于更复杂的格式string,您需要使用正则expression式:
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)
还要注意,你需要转换所有types的转换函数。 例如,上面我使用了类似的东西:
strtobool = lambda s: {'true': True, 'false': False}[s]
还有parse
模块。
parse()
被devise为与format()
(Python 2.6及更高版本中的新的string格式化函数format()
相反。
>>> 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',) {}>
您可以使用re
模块分割一系列字符。
>>> import re >>> r = re.compile('[ \t\n\r:]+') >>> r.split("abc:def ghi") ['abc', 'def', 'ghi']
你可以使用命名组来parsing模块。 它不会将子stringparsing为它们的实际数据types(例如int
),但是在parsingstring时非常方便。
从/proc/net/tcp
此示例行:
line=" 0: 00000000:0203 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 335 1 c1674320 300 0 0 0"
用variables模拟你的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'}
有一个ActiveState的配方,实现了一个基本的scanf http://code.activestate.com/recipes/502213-simple-scanf-implementation/
你可以把“:”变成空格,然后执行split.eg
>>> f=open("/proc/net/dev") >>> for line in f: ... line=line.replace(":"," ").split() ... print len(line)
没有正则expression式需要(在这种情况下)
Upvoted orip的答案。 我认为使用re模块是合理的build议。 Kodos应用程序在使用Python进行复杂的正则expression式任务时非常有用。
更新:正则expression式模块的Python文档re
包括一个关于模拟scanf的部分,我发现比上面的任何答案都更有用。
如果分隔符是':',则可以在':'上分割,然后在string上使用x.strip()来除去任何前导或尾部的空白。 int()将忽略空格。
odiak有一个Python 2的实现 。