Отдельные разделы документа - PullRequest
       11

Отдельные разделы документа

0 голосов
/ 07 сентября 2018

Я должен разобрать документ, который имеет вложенную структуру.

Содержит разделы с заголовком и парами ключей и значений.

txt_1 = '''
header1:
  key1: 1a
  key2: 2b
'''

txt_2 = '''
section1:
  key1: 1a

section2:
  key2: 2b
  key3: 3c
'''

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

HEADER = (
    (
        Word(alphanums)
        + Suppress(Literal(':'))
    ).setResultsName('header')
)
PARAM = Word(alphanums).setResultsName('param')
VALUE = Word(alphanums).setResultsName('value')

LINE = (
    Group(
        PARAM
        + Suppress(Literal(':'))
        + VALUE
    )
)

LINES = (
    OneOrMore(
        LINE
    )
).setResultsName('body')

SECTION = (
    Group(
        HEADER
        + LINES
    )
    .setResultsName('section')
)

GRAMMAR = OneOrMore(SECTION).setResultsName('section')

GRAMMAR.parseString(txt).asList()

для txt_1 работает нормально, но для txt_2, который имеет два раздела, разделенных пустой строкой, часть раздела 2 рассматривается как часть раздела 1.

[['section1', ['key1', '1a'], ['section2', 'key2']]]

Я пробовал другой подход со следующими токенами, но безуспешно.

N = White('\n', exact=1)
EMPTY = LineStart()+LineEnd()

1 Ответ

0 голосов
/ 07 сентября 2018

Замечание о том, что новый раздел начинается с шаблона " alphanum: alphanum: ", используется в приведенном ниже коде. Отрицательный взгляд ~ ( NotAny ) используется, чтобы не дать парсеру body сожрать заголовок следующего раздела.

Параметр setResultsName listAllMatches задается для имени результата line (суффикс *), так что в словаре может отображаться несколько совпадений.

pyparsing по умолчанию пропускает пробел, за исключением определенных ситуаций, например, при использовании Combine , поэтому здесь нет необходимости его рассматривать.

from pyparsing import *

COLON = Suppress(':')
param = Word(alphanums)("param")
value = Word(alphanums)("value")

line = Group(param + COLON + value)
new_section_check = (Word(alphanums) + COLON) * 2
body = OneOrMore(~new_section_check + line("line*"))

section = Group(Word(alphanums)("section") + COLON + body)
contents = OneOrMore(section)

text = """
section1:
  key1: 1a

section2:
  key2: 2b
  key3: 3c
"""

print(contents.parseString(text).dump())

, который производит следующее:

[['section1', ['key1', '1a']], ['section2', ['key2', '2b'], ['key3', '3c']]]
[0]:
  ['section1', ['key1', '1a']]
  - line: [['key1', '1a']]
    [0]:
      ['key1', '1a']
      - param: 'key1'
      - value: '1a'
  - section: 'section1'
[1]:
  ['section2', ['key2', '2b'], ['key3', '3c']]
  - line: [['key2', '2b'], ['key3', '3c']]
    [0]:
      ['key2', '2b']
      - param: 'key2'
      - value: '2b'
    [1]:
      ['key3', '3c']
      - param: 'key3'
      - value: '3c'
  - section: 'section2'
...