假设我有一个这样的项目符号列表:
* list item 1
* list item 2 (a parent)
** list item 3 (a child of list item 2)
** list item 4 (a child of list item 2 as well)
*** list item 5 (a child of list item 4 and a grand-child of list item 2)
* list item 6
我想将其解析为嵌套列表或其他一些数据结构,这使得元素之间的父子关系显式化(而不是依赖于它们的内容和相对位置)。例如,这是一个元组列表,其中包含一个项目及其子项列表(等等):
编辑:希望是一个更正确的列表示例,其中列表中的每个元素都是一个元组,其中包含:子弹的文本以及子项列表(如果适用)(以相同的形式)。
<击> 撞击>
<击>[('list item 1',), ('list item 2', [('list item 3',), ('list item 4', [('list item 5',)])] ('list item 6',)]击>
<击> 撞击>
[('list item 1',),
('list item 2', [('list item 3',), ('list item 4', [('list item 5',)])]),
('list item 6',)]
我试图用纯Python和一些Pyparsing实验来做这件事,但我没有取得进展。我有两个主要问题:
答案 0 :(得分:5)
在搜索算法的视图中,您提供的项目符号实际上是由Depth-First-Search生成的序列。所以我的策略是用dfs-sequence重建树结构。
以下是python代码:
from collections import deque
def dfsBullet(bullet,depth):
"""
parse the subtree with depth and the startnode of bullet[0]
"""
li = []
if depth != 0:
item = bullet.popleft()
li.append(item.split(' ',1)[1])
while (len(bullet) != 0):
item = bullet[0]
#apply same algo to the child node
if len(item.split(' ',1)[0]) > depth:
sublist = dfsBullet(bullet, len(item.split(' ')[0]))
#we have traverse all childnode, so go back
else:
return li
#add child tree to the list
li.append(sublist)
return li
答案 1 :(得分:2)
我无法解析你想要的结果 - 它似乎比相应的闭括号有更多的开括号,我不明白它背后的逻辑。
为了使树结构明确,例如:
data = '''* list item 1
* list item 2
** list item 3
** list item 4
*** list item 5
* list item 6'''.splitlines()
class Node(object):
def __init__(self, payload):
self.payload = payload
self.children = []
def show(self, indent):
print ' '*indent, self.payload
for c in self.children:
c.show(indent+2)
def makenest(linelist):
rootnode = Node(None)
stack = [(rootnode, 0)]
for line in linelist:
for i, c in enumerate(line):
if c != '*': break
stars, payload = line[:i], line[i:].strip()
curlev = len(stars)
curnod = Node(payload)
while True:
parent, level = stack[-1]
if curlev > level: break
del stack[-1]
# a child node of the current top-of-stack
parent.children.append(curnod)
stack.append((curnod, curlev))
rootnode.show(0)
makenest(data)
当然,show
方法的存在只是为了验证解析字符串和创建树的部分是否正常工作。如果你可以更准确地指定你想要将树转换为嵌套元组和列表的确切方式,我相信很容易将类Node
添加到类class Node
中 - 那么,请你给出这个缺失的规范......?
编辑:既然OP现在已经澄清了,它确实很容易满足规范。只需将以下方法添加到 def emit(self):
if self.children:
return (self.payload,
[c.emit() for c in self.children])
else:
return (self.payload,)
:
makenest
并将代码的最后三行(makenest
的最后一行,空白的一行,以及对 return [c.emit() for c in rootnode.children]
print(makenest(data))
的模块级调用)更改为:
print
([('list item 1',), ('list item 2', [('list item 3',), ('list item 4', [('list item 5',)])]), ('list item 6',)]
之后的括号是冗余的但在Python 2中是无害的,在Python 3中是必需的,所以我把它们放在那里以防万一; - )。
通过这些微小的更改,我的代码按照要求运行,现在发出
{{1}}
答案 2 :(得分:1)
跟踪您正在解析的当前“深度”。