Разбор файла конфигурации с тем же именем раздела в Python - PullRequest
8 голосов
/ 26 марта 2012

Я пытаюсь разобрать файл как:

[account]
User = first

[account]
User = second

Я использую ConfigParser в Python, но когда я читаю файл:

Config = configparser.ConfigParser()
Config.read(file)
print (Config.sections())

У меня ошибка:

While reading from ... : section 'account' already exists

Как я могу разобрать этот файл?Есть еще какая-нибудь библиотека?(предпочитаю для python3)

Ответы [ 4 ]

15 голосов
/ 27 марта 2012

Если вам нужно просто объединить разделы с одинаковыми именами (победит последний), просто передайте опцию strict=False конструктору (добавлен в Python 3.2).Вы фактически получаете поведение dict.update(), когда дублирующиеся разделы объединяются.

Config = configparser.ConfigParser(strict=False)

Однако из примеров данных ОП видно, что разделы с одинаковыми именами необходимо хранить отдельно, чтобы избежать потери данных.ConfigParser сохраняет разделы, которые он читает, в словаре, поэтому он не может обрабатывать несколько разделов с одинаковыми именами.К счастью, конструктор принимает аргумент dict_type, который позволяет указать другой словарь-подобный объект.Вы можете использовать это для поддержки разделов с одинаковыми именами.Вот грубое решение, которое искажает имена разделов, добавляя уникальный номер всякий раз, когда имя раздела было замечено ранее.

from collections import OrderedDict

class multidict(OrderedDict):
    _unique = 0   # class variable

    def __setitem__(self, key, val):
        if isinstance(val, dict):
            self._unique += 1
            key += str(self._unique)
        OrderedDict.__setitem__(self, key, val)

Config = configparser.ConfigParser(defaults=None, dict_type=multidict, strict=False)

Немного поработав, вы сможете создать более чистое решение.

2 голосов
/ 21 апреля 2017

На последнем питоне есть опция, которая может делать то, что вы хотите: ConfigParser(strict=True)

Cf: https://docs.python.org/3/library/configparser.html#configparser.ConfigParser

1 голос
/ 27 марта 2012

К сожалению, формат предоставленного INI-файла не соответствует стандартам.Имя раздела должно быть уникальным в документе.

Если вы можете изменить формат файла (я уже читал, что вы не можете, но для полноты ...), то такое решение будет уместным:

[accounts]
keys= account1, account2

[account1]
User = first

[account2]
User = second

Если вы действительно не можете чередовать формат файла, то я боюсь, что вы можете только вручную проанализировать файл конфигурации.

0 голосов
/ 24 марта 2017

» Если вы отклоняетесь от стандарта RFC и создаете свой собственный формат конфигурации, вам придется написать свой собственный синтаксический анализатор. "This http://www.tek -tips.com / viewthread.cfm? Qid = 1110829 работал для меня. Я сделал несколько небольших изменений. ** форматирование не получилось правильно после публикации

def configToDict(file):
# open the file
file = open('settings.cfg')

# create an empty dict
sections = {}

for line in file.readlines():
    # get rid of the newline
    line = line[:-1]
    try:
        # this will break if you have whitespace on the "blank" lines
        if line:
            # skip comment lines
            if line[0] == '#': next
            # this assumes everything starts on the first column
            if line[0] == '[':
                # strip the brackets
                section = line[1:-1]
                # create a new section if it doesn't already exist
                if not sections.has_key(section):
                    sections[section] = {}
            else:
                # split on first the equal sign
                (key, val) = line.split('=', 1)
                # create the attribute as a list if it doesn't
                # exist under the current section, this will
                # break if there's no section set yet
                if not sections[section].has_key(key):
                    sections[section][key] = []
                # append the new value to the list
                sections[section][key].append(val)
    except Exception as e:
        print str(e) + "line:" +line
return sections
...