Python中的sscanf

Mat*_*ner 59 python parsing split scanf procfs

我正在寻找与sscanf()Python 相当的东西.我想解析/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);
Run Code Online (Sandbox Code Playgroud)

我首先想到的是str.split,但是它不会拆分给定的字符,而是整个sep字符串:

>>> lines = open("/proc/net/dev").readlines()
>>> for l in lines[2:]:
>>>     cols = l.split(string.whitespace + ":")
>>>     print len(cols)
1
Run Code Online (Sandbox Code Playgroud)

如上所述,应该返回17.

是否有一个等价于sscanf(不是RE)的Python ,或者标准库中的字符串拆分函数,它分裂了我不知道的任何一系列字符?

Cra*_*een 65

还有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',) {}>
Run Code Online (Sandbox Code Playgroud)

  • 这才是真正的答案! (4认同)
  • 这个解决方案干净清晰,但您需要安装“parse”包。 (2认同)

Chr*_*lin 59

当我处于C语言中时,我通常使用zip和列表推理来实现类似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)
Run Code Online (Sandbox Code Playgroud)

请注意,对于更复杂的格式字符串,您需要使用正则表达式:

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)
Run Code Online (Sandbox Code Playgroud)

另请注意,您需要转换所有要转换的类型的转换函数.例如,上面我使用了类似的东西:

strtobool = lambda s: {'true': True, 'false': False}[s]
Run Code Online (Sandbox Code Playgroud)

  • 这似乎是一个很好的解决方案;遗憾的是 `bool("false")` 返回了 `True`,因为只有空字符串的计算结果为 `False`。但是,一切都没有丢失,您可以用自定义函数替换“bool”,该函数的行为方式符合您的要求。 (2认同)

Mik*_*ham 29

Python没有sscanf等效的内置函数,并且大多数情况下,通过直接使用字符串,使用正则表达式或使用解析工具来解析输入实际上更有意义.

可能对翻译C大多有用,人们已经实现了sscanf,例如在这个模块中:http://hkn.eecs.berkeley.edu/~dyoo/python/scanf/

在这种特殊情况下,如果您只想基于多个拆分字符拆分数据,那么re.split它确实是正确的工具.

  • 我确实说过不重新,但你很好地证明了这一点 (2认同)

Die*_*Epp 23

您可以使用该re模块拆分一系列字符.

>>> import re
>>> r = re.compile('[ \t\n\r:]+')
>>> r.split("abc:def  ghi")
['abc', 'def', 'ghi']
Run Code Online (Sandbox Code Playgroud)


ori*_*rip 14

您可以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"
Run Code Online (Sandbox Code Playgroud)

使用变量模仿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'}
Run Code Online (Sandbox Code Playgroud)