Найти - Пользователи
Полная версия: Парсинг конфигурационного файла. regexp или другое
Начало » Python для новичков » Парсинг конфигурационного файла. regexp или другое
1 2 3 4 5 6
aivs
Быстродействие хочу добиться, чтобы научиться писать программы с правильным кодом.
Версия той программы которую пишу на python, я уже написал на баше с использованием sed. Поэтому сейчас главный смысл - это обучение!
Ed
Желание писать “с правильным кодом” ортогонально желанию писать быстрые программы. Вот возьмем тот же readlines или построчное чтение. Если речь идет об обработке файлов большого размера либо большого количества файлов параллельно, то использование readlines категорически противопоказано из-за существенно больших требований к памяти по сравнению с чтением построчно. С точки зрения быстродействия, возможно, вариант с readlines будет быстрее. Какой код будет ‘правильным’ зависит от решаемой задачи.
aivs
Вот вариант редактирования конфига без regexp.
Как работает:
1) Читаем все строки в файле, все таки с помощью readlines
2) Вычисляем номер строки, которая начинается начинается с нужного параметра, использую метод строки startswith(), который в каждой строке проверяет первую подстроку, при нахождении такой строки, поиск останавливается.
3) Разбиваем строку на подстроки, разделить “=”
4) У второй подстроки (значение) убираем пробелы, если они есть
5) Сохраняю старое значение (потом пригодится)
6) Изменяю значение и склеиваю обратно все в строку
7) Записываю в файл

#!/usr/bin/python

# edit_rcconf.py

""" Функция редактирования конфигурационного файла rc.conf,
вызывается: rcconf_edit("параметр","значение") """
def rcconf_edit(param, setting):

# Читаем все строки в файле
config = open('rc.conf').readlines()

# Вычисляем номер строки, которая начинается с gateway
num_line = 0 #Номер строки
for line in config:
# Если строка N num_line начинается со слова param
if config[num_line].startswith(param):
break
num_line+=1

# Разбиваем строку на слова
param_sett = config[num_line].split("=")

# Очищаем значение параметра от пробелом и сохраняем в переменную old_setting
old_setting = param_sett[1].strip()

# Заменяем строку "параметр = значение" на новую
param_sett[1] = setting + "\n"
config[num_line] = '='.join(param_sett)

# Записываем новый конфиг в файл
with open('rc.conf', 'w') as config_write:
config_write.writelines(config)

# Вызываем функцию редактрирования rc.conf
rcconf_edit("address", "192.168.1.116")
При однократном выполнении эта функция выполняется на десятитысячную секунду быстрее чем функция с re.
Ed
У вас же задача стоит несколько параметров поменять, разве нет? Будете так для каждого параметра делать?

Я бы делал как-нибудь так:
from os import linesep, rename

fname = 'rc.conf'
new_name = '%s.new' % fname
with open(fname) as inf, open(new_name, 'w') as outf:
for line in inf:
for name,value in (("interface", "eth0"), ("address", "192.168.1.100"),
("netmask", "255.255.255.0"), ("gateway", "192.168.1.1")):
if line.startswith(name):
line = "%s=%s%s" % (name, value, linesep)
break
outf.write(line)
rename(new_name, fname)
У меня на моем старом лэптопе X60s это занимает 0m0.038s. Вам нужно большее быстродействие? Сомневаюсь.
o7412369815963
Ed
    for line in inf:
for name,value in (("interface", "eth0"), ("address", "192.168.1.100"),
("netmask", "255.255.255.0"), ("gateway", "192.168.1.1")):
if line.startswith(name):
line = "%s=%s%s" % (name, value, linesep)
break
outf.write(line)
я б тут через словарь сделал
    d = dict([("interface", "eth0"), ("address", "192.168.1.100"), ("netmask", "255.255.255.0"), ("gateway", "192.168.1.1")])
for line in inf:
name = line.split('=')[0].split()
if name in d:
line = "%s=%s%s" % (name, d[name], linesep)
outf.write(line)
aivs
Да действительно, для каждого параметра вызывать функцию, не быстро получится. Использую предложенные варианты.
o7412369815963 чем словарь лучше в данной ситуации? Мне кажется словарь больше ресурсов потребляет, чем список ?!
s0rg
Я бы предложил такой вариант:
#/usr/bin/env python
#-*-coding: utf8 -*-


class CfgParser(object):
'''
Dict-like unix config files parser

cfg = CfgParser('/etc/someconfig.cfg')
print cfg['SOMEVAL']
cfg['NEW_STR_VAL'] = 'somestring'
cfg['NEW_INT_VAL'] = 42

print cfg

fd = open('/etc/someconfig.cfg', 'w')
fd.write(repr(cfg))
fd.close()
'''

def __init__(self, config=None):
self._data = list()

if config is not None:
with open(config) as fd:
self.load_lines(fd)

def load_lines(self, iterable):
'''
Parse trough iterable that contains lines
'''
for line in iterable:
strp = line.strip()
if '=' not in strp or \
strp[0] in ('#', ';'):
self._data.append(('_COMMENT_', strp))
else:
name, value = strp.split('=')
self._data.append((name, value))

def _find_key(self, fkey):
'''
Find a key inside self._data
Returns: tuple (index, value)
or (None, None) if key not exists
'''
if fkey != '_COMMENT_':
for idx, key_val in enumerate(self._data):
key, val = key_val
if key == fkey:
return (idx, val.strip('\'\"'))
return (None, None)

def __getitem__(self, key):
_, val = self._find_key(key)
if val is None:
raise IndexError
return val

def __setitem__(self, key, value):
idx, _ = self._find_key(key)
val = ('"%s"' % value) if isinstance(value, basestring) else value
if idx is None:
self._data.append((key, val))
else:
self._data[idx] = (key, val)

def __delitem__(self, key):
idx, _ = self._find_key(key)
if idx is None:
raise IndexError
del self._data[idx]

def __repr__(self):
return '\n'.join(["%s = %s" % (key, val) if key != '_COMMENT_' else val
for key, val in self._data])


if __name__ == '__main__':
import sys

CONFIG_NAME = './rc.conf'

def main(argv=None):
cfg = CfgParser(CONFIG_NAME)

cfg['NEW_STRING'] = 'test'
cfg['NEW_INT'] = 89998
cfg['HARDWARECLOCK'] = 'remote_type'
print cfg

return 0

sys.exit(main(sys.argv))
o7412369815963
aivs
Да действительно, для каждого параметра вызывать функцию, не быстро получится. Использую предложенные варианты.
o7412369815963 чем словарь лучше в данной ситуации? Мне кажется словарь больше ресурсов потребляет, чем список ?!
В данной ситуации любой вариант подойдет т.к. входные данные и обработка смешных размеров.

А если вообще, то получение значения по ключу из словаря в сто-пицот раз быстрее чем поиск перебором.
т.е. тут "dict“ vs ”for name in xxx: if name == x"
s0rg
o7412369815963
А если вообще, то получение значения по ключу из словаря в сто-пицот раз быстрее чем поиск перебором.
Это да - но нужно сохранить первоначальную структуру данных.
aivs
s0rg
Это да - но нужно сохранить первоначальную структуру данных.
Именно так!
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB