Mam listę taki jak:

- launchers
   - say hello
      - command: echo "hello" | festival --tts
      - icon: sayHello.png
   - say world
      - command: echo "world" | festival --tts
      - icon: sayWorld.png
   - wait
      - command: for ((x = 0; x < 10; ++x)); do :; done
      - icon: wait.png

Chciałbym przeanalizować go do słownika takiego:

{
    "launchers": {
        "say hello": {
            "command": "echo \"hello\" | festival --tts",
            "icon": "sayHello.png"
        }
        "say world": {
            "command": "echo \"world\" | festival --tts",
            "icon": "sayWorld.png"
        }
        "wait": {
            "command": "for ((x = 0; x < 10; ++x)); do :; done",
            "icon": "wait.png"
        }
    }
}

Zacząłem na kilku bardzo ręcznym kodzie, który liczy wiodące spacje (np. len(line.rstrip()) - len(line.rstrip().lstrip())), ale zastanawiam się, czy istnieje bardziej rozsądny sposób podejścia do tego. Zdaję sobie sprawę, że JSON może być importowany do Pythona, ale to nie pasuje do moich celów. Jak więc lista markidown w pliku zostanie przeanalizowana do słownika w Pythonie? Czy istnieje skuteczny sposób na to?

Oto kilka podstawowych kodu, z którymi gram teraz:

for line in open("configuration.md", 'r'):
    indentation = len(line.rstrip()) - len(line.rstrip().lstrip())
    listItem = line.split('-')[1].strip()
    listItemSplit = listItem.split(':')
    key = listItemSplit[0].strip()
    if len(listItemSplit) == 2:
        value = listItemSplit[1].strip()
    else:
        value = ""
    print(indentation, key, value)
3
d3pd 14 sierpień 2014, 00:08

2 odpowiedzi

Najlepsza odpowiedź

Zakładałbym bardziej sztywny format i użyję stosu i wyrażenia regularnego:

import re    

line = re.compile(r'( *)- ([^:\n]+)(?:: ([^\n]*))?\n?')
depth = 0
stack = [{}]
for indent, name, value in line.findall(inputtext):
    indent = len(indent)
    if indent > depth:
        assert not stack[-1], 'unexpected indent'
    elif indent < depth:
        stack.pop()
    stack[-1][name] = value or {}
    if not value:
        # new branch
        stack.append(stack[-1][name])
    depth = indent

result = stack[0]

To daje:

>>> import re
>>> inputtext = '''\
... - launchers
...    - say hello
...       - command: echo "hello" | festival --tts
...       - icon: sayHello.png
...    - say world
...       - command: echo "world" | festival --tts
...       - icon: sayWorld.png
...    - wait
...       - command: for ((x = 0; x < 10; ++x)); do :; done
...       - icon: wait.png
... '''
>>> line = re.compile(r'( *)- ([^:\n]+)(?:: ([^\n]*))?\n?')
>>> depth = 0
>>> stack = [{}]
>>> for indent, name, value in line.findall(inputtext):
...     indent = len(indent)
...     if indent > depth:
...         assert not stack[-1], 'unexpected indent'
...     elif indent < depth:
...         stack.pop()
...     stack[-1][name] = value or {}
...     if not value:
...         # new branch
...         stack.append(stack[-1][name])
...     depth = indent
... 
{'command': 'echo "hello" | festival --tts', 'icon': 'sayHello.png'}
{'command': 'echo "world" | festival --tts', 'icon': 'sayWorld.png'}
>>> result = stack[0]
>>> from pprint import pprint
>>> pprint(result)
{'launchers': {'say hello': {'command': 'echo "hello" | festival --tts',
                             'icon': 'sayHello.png'},
               'say world': {'command': 'echo "world" | festival --tts',
                             'icon': 'sayWorld.png'},
               'wait': {'command': 'for ((x = 0; x < 10; ++x)); do :; done',
                        'icon': 'wait.png'}}}

Z tekstu wejściowego.

4
Martijn Pieters 13 sierpień 2014, 20:45

Czy uważałeś, że parsowanie markidown, a następnie wysyłając wyjście do parsera HTML?

Możesz użyć pakiet Markdown przeanalizować markdown do HTML.

Następnie możesz użyć wbudowanego HTMLPARSER Library, aby znaleźć listę i przewidywanie wartości. Alternatywnie można użyć LXML, aby przeanalizować HTML.

W ten sposób nie musisz się martwić o różne możliwe poziomy wcięcia. Biblioteka Markdown dba o to dla Ciebie i konwertuje go do formatu, które można łatwo wykonać dodatkową przetwarzanie.

3
nhinkle 13 sierpień 2014, 20:19