Подтвердить что ты не робот

Sscanf в Python

Я ищу эквивалент sscanf() в Python. Я хочу разбирать файлы /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, как объяснялось выше.

Существует ли эквивалент Python для sscanf (не RE) или функция разделения строк в стандартной библиотеке, которая разбивается на любой из диапазона символов, о которых я не знаю?

4b9b3361

Ответ 1

Python не имеет эквивалентного встроенного sscanf, и большую часть времени на самом деле имеет смысл разбирать ввод, непосредственно работая с строкой, используя регулярные выражения или используя инструмент синтаксического анализа.

Вероятно, в основном полезно для перевода C, люди внедрили sscanf, например, в этом модуле: http://hkn.eecs.berkeley.edu/~dyoo/python/scanf/

В этом конкретном случае, если вы просто хотите разделить данные на основе нескольких разделительных символов, re.split действительно является правильным инструментом.

Ответ 2

Когда я нахожусь в настроении C, я обычно использую методы zip и list для поведения типа 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]

Ответ 3

Существует также модуль 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',) {}>

Ответ 4

Вы можете разбить на диапазон символов с помощью модуля re.

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

Ответ 5

Вы можете проанализировать модуль 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"

Пример, подражающий вашему примеру 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'}

Ответ 7

вы можете повернуть ":" в пространство и сделать split.eg

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

нет необходимости в регулярном выражении (для этого случая)

Ответ 8

Упрощенный orip ответ. Я думаю, что это разумный совет по использованию модуля re. Приложение Kodos полезно при приближении к сложной задаче regexp с Python.

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

Ответ 9

Обновление. Документация Python для своего модуля regex, re, содержит раздел по моделированию scanf, который я нашел более полезным, чем любой из приведенных выше ответов.

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

Ответ 10

Если разделители являются ":", вы можете разделить на ":", а затем использовать x.strip() в строках, чтобы избавиться от любого ведущего или конечного пробела. int() будет игнорировать пробелы.