pyparsing с одинаковой начальной и конечной строкой

Связано с: Python анализирует блоки в квадратных скобках

У меня есть файл следующего формата:

#
here
are
some
strings
#
and
some
others
 #
 with
 different
 levels
 #
 of
  #
  indentation
  #
 #
#

Таким образом, блок определяется начальным # и конечным #. Однако конечный # n-1-го блока также является начальным # n-го блока.

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

Начнем с того, что я начал с регулярных выражений, но довольно быстро отказался (думаю, вы догадались, почему), поэтому я попытался использовать pyparsing, но я не могу просто написать

print(nestedExpr('#','#').parseString(my_string).asList())

Потому что это вызывает исключение ValueError (ValueError: opening and closing strings cannot be the same).

Зная, что я не могу изменить формат ввода, есть ли у меня лучший вариант, чем pyparsing для этого?

Я также пытался использовать этот ответ: https://stackoverflow.com/a/1652856/740316 и заменил {/ } с #/#, но не может разобрать строку.


person Community    schedule 08.04.2015    source источник
comment
Может быть, просто замените n-й # на что-то вроде #-#, а затем разделите или проанализируйте его на -.   -  person l'L'l    schedule 08.04.2015
comment
У меня нет возможности изменить формат ввода, к сожалению...   -  person    schedule 08.04.2015
comment
Вы хотите разделить все уровни как строки или только внешние (например, все подуровни строки будут включены в эту строку). А как насчет удаления пробелов, табуляции в строках?   -  person l'L'l    schedule 08.04.2015
comment
Ну, сначала я подумал о вашем последнем предложении, затем я бы рекурсивно повторил метод для выходной строки, поэтому первый шаг дал бы мне только внешние уровни с другими вложенными блоками в виде необработанных строк, а затем итерация по ним дала бы мне содержимое из этих вложенных блоков и т.д. Так что в основном ответ на ваш вопрос - это ваше первое предложение, но я хотел бы сохранить след уровня блока. Я не хочу, чтобы все блоки были сведены в одномерный список, если вы понимаете, что я имею в виду.   -  person    schedule 08.04.2015


Ответы (1)


К сожалению (для вас), ваша группировка зависит не только от разделяющих символов '#', но и от уровней отступа (иначе ['with','different','levels'] был бы на том же уровне, что и предыдущая группа ['and','some','others']). Синтаксический анализ грамматик, чувствительных к отступам, не является сильной стороной pyparsing — это можно сделать, но это неприятно. Для этого мы будем использовать вспомогательный макрос pyparsing indentedBlock, который также требует, чтобы мы определили переменную списка, которую indentedBlock может использовать для своего стека отступов.

См. встроенные комментарии в приведенном ниже коде, чтобы увидеть, как вы можете использовать один подход с pyparsing и indentedBlock:

from pyparsing import *

test = """\
#
here
are
some
strings
#
and
some
others
 #
 with
 different
 levels
 #
 of
  #
  indentation
  #
 #
#"""

# newlines are significant for line separators, so redefine 
# the default whitespace characters for whitespace skipping
ParserElement.setDefaultWhitespaceChars(' ')

NL = LineEnd().suppress()
HASH = '#'
HASH_SEP = Suppress(HASH + Optional(NL))

# a normal line contains a single word
word_line = Word(alphas) + NL


indent_stack = [1]

# word_block is recursive, since word_blocks can contain word_blocks
word_block = Forward()
word_group = Group(OneOrMore(word_line | ungroup(indentedBlock(word_block, indent_stack))) )

# now define a word_block, as a '#'-delimited list of word_groups, with 
# leading and trailing '#' characters
word_block <<= (HASH_SEP + 
                 delimitedList(word_group, delim=HASH_SEP) + 
                 HASH_SEP)

# the overall expression is one large word_block
parser = word_block

# parse the test string
parser.parseString(test).pprint()

Отпечатки:

[['here', 'are', 'some', 'strings'],
 ['and',
  'some',
  'others',
  [['with', 'different', 'levels'], ['of', [['indentation']]]]]]
person PaulMcG    schedule 09.04.2015