代码之家  ›  专栏  ›  技术社区  ›  Matt Joiner

python中的scsanf

  •  55
  • Matt Joiner  · 技术社区  · 15 年前

    我在找一个相当于 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。

    有相当于 sscanf (不是re),还是标准库中的字符串拆分函数,对我不知道的任何字符范围进行拆分?

    11 回复  |  直到 7 年前
        1
  •  27
  •   Mike Graham    15 年前

    巨蟒没有 sscanf 相当于内置的,而且大多数时候,通过直接使用字符串、使用regexps或使用解析工具来解析输入实际上更有意义。

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

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

        2
  •  58
  •   Craig McQueen Dr. Watson    7 年前

    还有 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',) {}>
    
        3
  •  57
  •   Chris Dellin    7 年前

    当我处于C型情绪时,我通常使用压缩和列表理解来理解类似于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)
    

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

    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]
    
        4
  •  23
  •   Dietrich Epp    15 年前

    您可以使用 re 模块。

    >>> import re
    >>> r = re.compile('[ \t\n\r:]+')
    >>> r.split("abc:def  ghi")
    ['abc', 'def', 'ghi']
    
        5
  •  13
  •   orip    15 年前

    你可以用模块解析 re 使用 named groups . 它不会将子字符串解析为它们的实际数据类型(例如 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'}
    
        6
  •  2
  •   markovg    14 年前

    有一个ActiveState配方可以实现基本的scanf http://code.activestate.com/recipes/502213-simple-scanf-implementation/

        7
  •  1
  •   ghostdog74    15 年前

    您可以将“:”转换为空格,然后进行拆分。

    >>> f=open("/proc/net/dev")
    >>> for line in f:
    ...     line=line.replace(":"," ").split()
    ...     print len(line)
    

    不需要regex(在这种情况下)

        8
  •  1
  •   codeasone    14 年前

    反对奥里普的回答。我认为使用RE模块是合理的建议。当使用python处理复杂的regexp任务时,kodos应用程序非常有用。

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

        9
  •  1
  •   Jon    8 年前

    更新:其regex模块的python文档, re 包括一个关于模拟scanf的部分,我发现它比上面的任何答案都有用。

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

        10
  •  0
  •   Lennart Regebro    15 年前

    如果分隔符是“:”,则可以在“:”上拆分,然后在字符串上使用x.strip()来除去任何前导或尾随空格。int()将忽略空格。

        11
  •  0
  •   Janus Troelsen    12 年前