python parsing split scanf procfs

sscanf en Python



parsing split (11)

Estoy buscando un equivalente a sscanf() en Python. Quiero analizar /proc/net/* archivos, en CI podría hacer algo como esto:

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);

Al principio pensé en usar str.split , sin embargo, no se divide en los caracteres dados, sino en la cadena sep como un todo:

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

Que debería devolver 17, como se explicó anteriormente.

¿Existe un Python equivalente a sscanf (no RE), o una función de división de cadenas en la biblioteca estándar que se divide en cualquiera de un rango de caracteres que no conozco?



Cuando estoy de humor C, generalmente uso compresión y lista de comprensiones para un comportamiento similar al scanf. Me gusta esto:

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)

Tenga en cuenta que para cadenas de formato más complejas, necesita usar expresiones regulares:

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)

Tenga en cuenta también que necesita funciones de conversión para todos los tipos que desee convertir. Por ejemplo, arriba he usado algo como:

strtobool = lambda s: {''true'': True, ''false'': False}[s]




Puede analizar el módulo usando grupos nombrados . No analizará las subcadenas a sus tipos de datos reales (por ejemplo, int ) pero es muy conveniente para analizar cadenas.

Dada esta línea de muestra de /proc/net/tcp :

line=" 0: 00000000:0203 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 335 1 c1674320 300 0 0 0"

Un ejemplo que imita tu ejemplo de sscanf con la variable podría ser:

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''}


Puede dividir en un rango de caracteres usando el módulo re .

>>> import re >>> r = re.compile(''[ /t/n/r:]+'') >>> r.split("abc:def ghi") [''abc'', ''def'', ''ghi'']


Python no tiene un equivalente de sscanf incorporado, y la mayoría de las veces realmente tiene mucho más sentido analizar la entrada al trabajar directamente con la cadena, usar expresiones regulares o usar una herramienta de análisis sintáctico.

Probablemente más útil para traducir C, las personas han implementado sscanf , como en este módulo: http://hkn.eecs.berkeley.edu/~dyoo/python/scanf/

En este caso particular, si solo desea dividir los datos en función de múltiples caracteres divididos, re.split es realmente la herramienta adecuada.


Respuesta de orip vuelta arriba. Creo que es un buen consejo usar el módulo Re. La aplicación Kodos es útil al abordar una tarea de expresiones regulares complejas con Python.

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


Si los separadores son '':'', puede dividir en '':'', y luego usar x.strip () en las cadenas para deshacerse de cualquier espacio en blanco inicial o posterior. int () ignorará los espacios.


También está el módulo de parse .

parse() está diseñado para ser lo contrario de format() (la función de formateo de cadena más nueva en Python 2.6 y superior).

>>> 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'',) {}>


puede girar el ":" al espacio, y hacer el split.eg

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

no se necesitan expresiones regulares (para este caso)