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) или функция разделения строк в стандартной библиотеке, которая разбивается на любой из диапазона символов, о которых я не знаю?
Ответы
Ответ 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'}
Ответ 6
Существует рецепт ActiveState, который реализует базовый scanf
http://code.activestate.com/recipes/502213-simple-scanf-implementation/
Ответ 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() будет игнорировать пробелы.
Ответ 11
Существует версия Python 2 от odiak.