編集:明確化と仕様の変更のおかげで、コードを編集しましたが、明確にするNode
ための中間ステップとして明示的なクラスを使用しています-ロジックは、行のリストをノードのリストに変換し、次にそのリストを変換することですノードをツリーに(インデント属性を適切に使用して)作成し、そのツリーを読み取り可能な形式で出力します(これは、ツリーが適切に構築されていることを確認するための単なる「デバッグヘルプ」ステップであり、もちろんコメントアウトできます。スクリプトの最終バージョン-もちろん、デバッグ用にハードコードするのではなく、ファイルから行を取得します!-)、最後に目的のPython構造を構築して印刷します。これがコードです。後で説明するように、結果はOPが指定したものとほぼ同じですが、1つの例外がありますが、最初のコードは次のとおりです。
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エントリとして表示されることを除いて(ただし、リストが空になる場合は、おおよそ質問の例のように、メモのエントリは省略されます)。
質問の現在のバージョンでは、メモをどのように表現するかが少し不明確です。1つのメモはスタンドアロンの文字列として表示され、他のメモは値が文字列であるエントリとして表示されます(私が使用している文字列のリストではありません)。メモが1つのケースではスタンドアロンの文字列として、他のすべてのケースではdictエントリとして表示される必要があることを意味するものが明確ではないため、私が使用しているこのスキームはより規則的です。また、メモ(ある場合)がリストではなく単一の文字列である場合、ノードに複数のメモが表示されるとエラーになることを意味しますか?後者に関しては、私が使用しているこのスキームはより一般的です(ノードに、質問で明らかに示されている0または1だけでなく、0から上までの任意の数のノートを持たせます)。
目的のソリューションの99%を提供するために(事前編集の回答はほぼ同じくらい長く、仕様の明確化と変更に役立ちました)非常に多くのコードを記述したので、これが元のポスターを満足させることを願っています。それらを互いに一致させるためのコードおよび/または仕様は、彼にとって簡単なはずです!