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 ,但是它不会在给定的字符上分割,而是整个sepstring:

 >>> 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式任务时非常有用。

http://kodos.sourceforge.net/home.html

更新:正则expression式模块的Python文档re包括一个关于模拟scanf的部分,我发现比上面的任何答案都更有用。

https://docs.python.org/2/library/re.html#simulating-scanf

如果分隔符是':',则可以在':'上分割,然后在string上使用x.strip()来除去任何前导或尾部的空白。 int()将忽略空格。

odiak有一个Python 2的实现 。