문제

편집-1에서 업데이트된 입력 및 출력 데이터를 참조하세요.

내가 달성하려는 것은 변화하는 것입니다.

+ 1
 + 1.1
  + 1.1.1
   - 1.1.1.1
   - 1.1.1.2
 + 1.2
  - 1.2.1
  - 1.2.2
 - 1.3
+ 2
- 3

다음과 같은 파이썬 데이터 구조로

[{'1': [{'1.1': {'1.1.1': ['1.1.1.1', '1.1.1.2']}, '1.2': ['1.2.1', '1.2.2']}, '1.3'], '2': {}}, ['3',]]

나는 다양한 위키 마크업 언어, 마크다운, 재구성된 텍스트 등을 살펴보았지만 많은 양의 태그와 구문을 다루어야 하기 때문에 작동 방식을 이해하기가 매우 복잡합니다("목록"만 필요함). 이들 중 대부분은 HTML 대신 Python으로 변환되었습니다.)

나는 또한 토크나이저, 어휘분석기, 파서를 살펴보았지만 다시 말하지만 그것들은 내가 필요로 하는 것보다 훨씬 더 복잡하고 이해할 수 있습니다.

어디서부터 시작해야 할지 모르겠으며 이 주제에 관해 도움을 주시면 감사하겠습니다.감사해요

편집-1:예, 줄 시작 부분의 문자가 중요합니다. 이전의 필수 출력에서 ​​이제 볼 수 있습니다. * 자식이 있는 루트 노드를 나타냅니다. + 아이들이 있고 - 자식(루트 등)이 없으며 해당 노드와 관련된 추가 정보일 뿐입니다.그만큼 * 중요하지 않으며 다음과 같이 바꿔 사용할 수 있습니다. + (다른 방법으로 루트 상태를 얻을 수 있습니다.)

따라서 새로운 요구 사항은 다음을 사용하는 것입니다. * 자식이 있거나 없는 노드를 나타냅니다. - 아이를 가질 수 없습니다.또한 키가 다음 텍스트가 아니도록 변경했습니다. * 왜냐하면 나중에 실제 제목으로 바뀔 것이기 때문입니다.

예를 들어

* 1
 * 1.1
 * 1.2
  - Note for 1.2
* 2
* 3
- Note for root

줄 것이다

[{'title': '1', 'children': [{'title': '1.1', 'children': []}, {'title': '1.2', 'children': []}]}, {'title': '2', 'children': [], 'notes': ['Note for 1.2', ]}, {'title': '3', 'children': []}, 'Note for root']

또는 Python으로 개요를 표현하는 또 다른 아이디어가 있다면 제안해 보세요.

도움이 되었습니까?

해결책

편집하다:사양의 설명과 변경 덕분에 코드를 편집했지만 여전히 명시적인 코드를 사용하고 있습니다. Node 클래스를 명확성을 위한 중간 단계로 사용합니다. 논리는 행 목록을 노드 목록으로 변환한 다음 해당 노드 목록을 트리로 변환하고(indent 속성을 적절하게 사용하여) 해당 트리를 읽을 수 있는 형식으로 인쇄하는 것입니다. (이것은 트리가 잘 구성되었는지 확인하기 위한 "디버그 도움말" 단계일 뿐이며 스크립트의 최종 버전에서 주석 처리될 수도 있습니다. 물론 파일에서 해당 행을 가져옵니다. 디버깅을 위해 하드코딩하는 대신!-) 마침내 원하는 Python 구조를 빌드하고 인쇄합니다.코드는 다음과 같습니다. 그 결과는 다음과 같습니다. 거의 OP가 한 가지 예외를 지정함에 따라 코드는 먼저 다음과 같습니다.

import sys

class Node(object):
  def __init__(self, title, indent):
    self.title = title
    self.indent = indent
    self.children = []
    self.notes = []
    self.parent = None
  def __repr__(self):
    return 'Node(%s, %s, %r, %s)' % (
        self.indent, self.parent, self.title, self.notes)
  def aspython(self):
    result = dict(title=self.title, children=topython(self.children))
    if self.notes:
      result['notes'] = self.notes
    return result

def print_tree(node):
  print ' ' * node.indent, node.title
  for subnode in node.children:
    print_tree(subnode)
  for note in node.notes:
    print ' ' * node.indent, 'Note:', note

def topython(nodelist):
  return [node.aspython() for node in nodelist]

def lines_to_tree(lines):
  nodes = []
  for line in lines:
    indent = len(line) - len(line.lstrip())
    marker, body = line.strip().split(None, 1)
    if marker == '*':
      nodes.append(Node(body, indent))
    elif marker == '-':
      nodes[-1].notes.append(body)
    else:
      print>>sys.stderr, "Invalid marker %r" % marker

  tree = Node('', -1)
  curr = tree
  for node in nodes:
    while node.indent <= curr.indent:
      curr = curr.parent
    node.parent = curr
    curr.children.append(node)
    curr = node

  return tree


data = """\
* 1
 * 1.1
 * 1.2
  - Note for 1.2
* 2
* 3
- Note for root
""".splitlines()

def main():
  tree = lines_to_tree(data)
  print_tree(tree)
  print
  alist = topython(tree.children)
  print alist

if __name__ == '__main__':
  main()

실행되면 다음이 방출됩니다.

 1
  1.1
  1.2
  Note: 1.2
 2
 3
 Note: 3

[{'children': [{'children': [], 'title': '1.1'}, {'notes': ['Note for 1.2'], 'children': [], 'title': '1.2'}], 'title': '1'}, {'children': [], 'title': '2'}, {'notes': ['Note for root'], 'children': [], 'title': '3'}]

키 순서(물론 중요하지 않으며 사전에서 보장되지 않음)를 제외하면 다음과 같습니다. 거의 요청한 대로 - 여기서는 제외 모두 메모는 키가 있는 dict 항목으로 나타납니다. notes 그리고 문자열 목록인 값(대략 질문의 예에서와 같이 목록이 비어 있으면 메모 항목이 생략됩니다).

현재 버전의 질문에서는 메모를 표현하는 방법이 약간 불분명합니다.한 메모는 독립형 문자열로 표시되고 다른 메모는 값이 문자열(사용 중인 문자열 목록 대신)인 항목으로 표시됩니다.어떤 경우에는 메모가 독립형 문자열로 나타나야 하고 다른 경우에는 dict 항목으로 나타나야 한다는 것을 의미하는 것이 무엇인지 명확하지 않습니다. 따라서 제가 사용하고 있는 이 체계는 더 규칙적입니다.메모(있는 경우)가 목록이 아닌 단일 문자열인 경우 노드에 대해 두 개 이상의 메모가 나타나면 오류가 있다는 의미입니까?후자의 경우, 내가 사용하고 있는 이 체계는 더 일반적입니다(질문에 암시된 것처럼 노드에 0이나 1이 아니라 0부터 임의의 수의 음표를 가질 수 있음).

원하는 솔루션의 99%를 제공하기 위해 너무 많은 코드를 작성했기 때문에(사전 편집 답변은 길이가 길었고 사양을 명확하게 하고 변경하는 데 도움이 되었습니다) (희망합니다) 99%의 원하는 솔루션을 제공했습니다. 코드 및/또는 사양을 서로 일치시키려면 그 사람이 쉽게 할 수 있어야 합니다!

다른 팁

개요 상황을 처리하고 있으므로 스택을 사용하여 작업을 단순화할 수 있습니다.기본적으로 다음과 같은 스택을 생성하려고 합니다. dicts는 윤곽선의 깊이에 해당합니다.새 줄을 구문 분석하고 윤곽선의 깊이가 증가하면 새 줄을 푸시합니다. dict 이전 스택에서 참조했던 스택에 dict 스택의 상단에 있습니다.깊이가 낮은 줄을 구문 분석할 때 스택을 팝하여 상위 항목으로 돌아갑니다.그리고 동일한 깊이를 가진 선을 만나면 이를 dict 스택의 상단에 있습니다.

스택은 트리를 구문 분석할 때 정말 유용한 데이터 구조입니다.마지막으로 추가된 노드부터 스택의 루트까지의 경로를 항상 유지하면 들여쓰기 길이로 올바른 부모를 찾을 수 있습니다.마지막 예제를 구문 분석하려면 다음과 같이 작동해야 합니다.

import re
line_tokens = re.compile('( *)(\\*|-) (.*)')

def parse_tree(data):
    stack = [{'title': 'Root node', 'children': []}]
    for line in data.split("\n"):
        indent, symbol, content = line_tokens.match(line).groups()        
        while len(indent) + 1 < len(stack):
            stack.pop() # Remove everything up to current parent
        if symbol == '-':
            stack[-1].setdefault('notes', []).append(content)
        elif symbol == '*':
            node = {'title': content, 'children': []}
            stack[-1]['children'].append(node)
            stack.append(node) # Add as the current deepest node
    return stack[0]

사용중인 구문은 다음과 같습니다 매우 Yaml과 유사합니다.몇 가지 차이점이 있지만 배우기가 매우 쉽습니다. 주요 초점은 사람이 읽고 쓸 수 있도록 하는 것입니다.

Yaml 웹사이트를 살펴보세요.거기에는 Python 바인딩, 문서 및 기타 항목이 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top