84 votes

sscanf en Python

Je suis à la recherche d'un équivalent de sscanf() en Python. Je veux analyser /proc/net/* fichiers en C je pourrais faire quelque chose comme ceci:

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

Je pensais au début à utiliser str.split, toutefois, il ne faut pas se déchirer sur les personnages, mais l' sep chaîne de caractères comme un ensemble:

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

Ce qui devrait être de retour le 17, comme expliqué ci-dessus.

Est-il un Python équivalent à sscanf (pas de RÉ), ou une chaîne de fractionnement de la fonction de la bibliothèque standard, qui se fend sur toute une gamme de personnages que je ne suis pas au courant?

100voto

Craig McQueen Points 13194

Il y a aussi le module parse .

parse() est conçu pour être l'opposé de format() (la nouvelle fonction de formatage de chaîne dans Python 2.6 et versions supérieures).

75voto

Chris Dellin Points 151

Quand je suis d'humeur C, j'utilise généralement des compréhensions zip et liste pour un comportement semblable à scanf. Comme ça:

 input = '1 3.0 false hello'
(a, b, c, d) = [t(s) for t,s in zip((int,float,bool,str),input.split())]
print (a, b, c, d)
 

Notez que pour les chaînes de format plus complexes, vous devez utiliser des expressions régulières:

 import re
input = '1:3.0 false,hello'
(a, b, c, d) = [t(s) for t,s in zip((int,float,bool,str),re.search('^(\d+):([\d.]+) (\w+),(\w+)$',input).groups())]
print (a, b, c, d)
 

38voto

Mike Graham Points 22480

Python n'a pas de sscanf équivalent intégré, et la plupart du temps il est en fait beaucoup plus de sens pour analyser l'entrée en travail à la chaîne directement, en utilisant les expressions régulières, ou à l'aide d'un outil d'analyse.

Probablement surtout utile pour la traduction C, les gens ont mis en oeuvre sscanf, comme dans ce module: http://hkn.eecs.berkeley.edu/~dyoo/python/scanf/

Dans ce cas particulier, si vous voulez juste pour diviser les données en fonction de plusieurs split personnages, re.split est vraiment le bon outil.

25voto

Dietrich Epp Points 72865

Vous pouvez diviser une plage de caractères en utilisant le module re .

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

16voto

orip Points 28225

Vous pouvez analyser avec le module re utilisant des groupes nommés . Il n'analysera pas les sous-chaînes avec leurs types de données réels (par exemple, int ), mais cela s'avère très pratique lors de l'analyse de chaînes.

Étant donné cet exemple de ligne 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 exemple imitant votre exemple sscanf avec la variable pourrait être:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X