Разбор неизвестной структуры данных в python - PullRequest
3 голосов
/ 26 июня 2009

У меня есть файл, содержащий множество данных, приведенных в форме, подобной этой:

Group1 {  
    Entry1 {  
        Title1 [{Data1:Member1, Data2:Member2}]  
        Title2 [{Data3:Member3, Data4:Member4}]  
    }  
    Entry2 {  
        ...  
    }  
}
Group2 {
    DifferentEntry1 {
        DiffTitle1 {
            ...
        }
    }
}

Дело в том, что я не знаю, сколько в скобках слоев и как структурированы данные. Мне нужно изменить данные и удалить всю запись в зависимости от условий, в которых участвуют члены данных, прежде чем записывать все в новый файл. Какой лучший способ чтения в таком файле? Спасибо!

Ответы [ 6 ]

3 голосов
/ 27 июня 2009

Вот грамматика.

dict_content : NAME ':' NAME [ ',' dict_content ]?
             | NAME '{' [ dict_content ]? '}' [ dict_content ]?
             | NAME '[' [ list_content ]? ']' [ dict_content ]?
             ;

list_content : NAME [ ',' list_content ]?
             | '{' [ dict_content ]? '}' [ ',' list_content ]?
             | '[' [ list_content ]? ']' [ ',' list_content ]?
             ;

Верхний уровень dict_content.

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

3 голосов
/ 26 июня 2009

Структура данных, по-видимому, представляет собой диктат, в котором ключи являются строками, а значение является либо строкой, либо другим диктом того же типа, поэтому я рекомендую, возможно, включить его в такую ​​структуру python,

например:

{'group1': {'Entry2': {}, 'Entry1': {'Title1':{'Data4': 'Member4',
'Data1': 'Member1','Data3': 'Member3', 'Data2': 'Member2'}, 
'Title2': {}}}

На верхнем уровне файла вы должны создать пустой dict, а затем для каждой прочитанной строки вы используете идентификатор в качестве ключа, а затем, когда вы видите {вы создаете значение для этого ключа в качестве dict , Когда вы видите Key: Value, то вместо того, чтобы создавать этот ключ как dict, вы просто вставляете значение как обычно. Когда вы видите}, вы должны «вернуться» к предыдущему диктату, над которым вы работали, и вернуться к его заполнению.

Я бы подумал, что весь этот синтаксический анализатор для помещения файла в структуру python, как это можно сделать в одной довольно короткой рекурсивной функции, которая просто вызывала себя, чтобы заполнить каждый поддикт, когда он увидел {и затем вернулся к своему звонящий при просмотре}

2 голосов
/ 26 июня 2009

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

1 голос
/ 27 июня 2009

У меня есть что-то похожее, но написано на Java. Он анализирует файл с той же базовой структурой и немного другим синтаксисом (без отступов '{' и '}', как в python). Это очень простой язык сценариев.

В основном это работает так: он использует стек для отслеживания самого внутреннего блока инструкций (или в вашем случае данных) и добавляет каждую новую инструкцию в блок сверху. Если он анализирует инструкцию, которая ожидает новый блок, он помещается в стек. Если блок заканчивается, он выталкивает один элемент из стека.

Я не хочу публиковать весь исходный код, потому что он большой и доступен по коду Google (lizzard-entertainment, revision 405). Есть несколько вещей, которые вам нужно знать.

  • Инструкция является абстрактным классом, и в нем есть метод block_expected, указывающий, нужен ли конкретной инструкции блок (например, циклы и т. Д.). В вашем случае в этом нет необходимости, вам нужно только проверить на '{'.
  • Блок расширяет инструкцию. Он содержит список инструкций и метод add, чтобы добавить больше.
  • indent_level возвращает количество пробелов, предшествующих тексту инструкции. Это также не нужно для '{}' singns.

заполнитель

BufferedReader input = null;
try {
    input = new BufferedReader(new FileReader(inputFileName));
    // Stack of instruction blocks
    Stack<Block> stack = new Stack<Block>();
    // Push the root block
    stack.push(this.topLevelBlock);
    String line = null;
    Instruction prev = new Noop();
    while ((line = input.readLine()) != null) {
        // Difference between the indentation of the previous and this line
        // You do not need this you will be using {} to specify block boundaries
        int level = indent_level(line) - stack.size();
        // Parse the line (returns an instruction object)
        Instruction inst = Instruction.parse(line.trim().split(" +"));
        // If the previous instruction expects a block (for example repeat)
        if (prev.block_expected()) {
            if (level != 1) {
                // TODO handle error
                continue;
            }
            // Push the previous instruction and add the current instruction
            stack.push((Block)(prev));
            stack.peek().add(inst);
        } else {
            if (level > 0) {
                // TODO handle error
                continue;
            } else if (level < 0) {
                // Pop the stack at the end of blocks
                for (int i = 0; i < -level; ++i)
                    stack.pop();
            }
            stack.peek().add(inst);
        }
        prev = inst;
    }
} finally {
    if (input != null)
        input.close();
}
1 голос
/ 26 июня 2009

Эта проблема очень похожа на обработку XML, и для этого есть много кода Python. Так что, если бы вы могли как-то преобразовать файл в XML, вы могли бы просто запустить его через анализатор из стандартной библиотеки. XML-версия вашего примера будет выглядеть примерно так:

<group id="Group1">  
    <entry id="Entry1">
        <title id="Title1"><data id="Data1">Member1</data> <data id="Data2">Member2</data></title>
        <title id="Title2"><data id="Data3">Member3</data> <data id="Data4">Member4</data></title>
    </entry>  
    <entry id="Entry2">  
        ...
    </entry>
</group>

Конечно, преобразование в XML, вероятно, не самая простая вещь, которую нужно сделать. Но ваша работа во многом схожа с тем, что уже было сделано с парсерами XML, у вас просто другой синтаксис для работы. Таким образом, вы могли бы взглянуть на некоторый код парсинга XML и написать небольшой синтаксический анализатор Python для вашего файла данных на основе этого. (В зависимости от того, как реализован синтаксический анализатор XML, вы можете даже скопировать код, просто измените несколько регулярных выражений и запустите его для своего файла)

1 голос
/ 26 июня 2009

Это зависит от того, как структурированы данные, и какие изменения вам нужно сделать.

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

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

Так что вам нужно лучше понять проблему, прежде чем вы узнаете, как лучше всего.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...