给定输入:

apple: banana eggplant
banana: cantaloupe durian
eggplant:
fig:

我想将其连接成以下格式:
├─ apple
│  ├─ banana
│  │   ├─ cantaloupe
│  │   └─ durian
│  └─ eggplant
└─ fig

可能有也可能没有多个根元素(在上面的示例中,有两个根元素),我想找到一个可以毫无问题地处理它们的解决方案。

是否有任何命令行工具可以处理这种转换?失败了,其他脚本语言中是否有任何东西可以稍微轻松地解决这一问题(我已经看过Python的pprint了,但我也不知道如何将其用于类似的事情)?

最佳答案

以下代码将产生您要求的树结构:

branch = '├'
pipe = '|'
end = '└'
dash = '─'


class Tree(object):
    def __init__(self, tag):
        self.tag = tag


class Node(Tree):
    def __init__(self, tag, *nodes):
        super(Node, self).__init__(tag)
        self.nodes = list(nodes)


class Leaf(Tree):
    pass


def _draw_tree(tree, level, last=False, sup=[]):
    def update(left, i):
        if i < len(left):
            left[i] = '   '
        return left

    print ''.join(reduce(update, sup, ['{}  '.format(pipe)] * level)) \
          + (end if last else branch) + '{} '.format(dash) \
          + str(tree.tag)
    if isinstance(tree, Node):
        level += 1
        for node in tree.nodes[:-1]:
            _draw_tree(node, level, sup=sup)
        _draw_tree(tree.nodes[-1], level, True, [level] + sup)


def draw_tree(trees):
    for tree in trees[:-1]:
        _draw_tree(tree, 0)
    _draw_tree(trees[-1], 0, True, [0])

它要求您使用给定的形式表示数据。

关于数据反序列化,您只需要跟踪父节点,以便当叶子看起来像是一个节点时,只需替换它即可:
class Track(object):
    def __init__(self, parent, idx):
        self.parent, self.idx = parent, idx


def parser(text):
    trees = []
    tracks = {}
    for line in text.splitlines():
        line = line.strip()
        key, value = map(lambda s: s.strip(), line.split(':', 1))
        nodes = value.split()
        if len(nodes):
            parent = Node(key)
            for i, node in enumerate(nodes):
                tracks[node] = Track(parent, i)
                parent.nodes.append(Leaf(node))
            curnode = parent
            if curnode.tag in tracks:
                t = tracks[curnode.tag]
                t.parent.nodes[t.idx] = curnode
            else:
                trees.append(curnode)
        else:
            curnode = Leaf(key)
            if curnode.tag in tracks:
                # well, how you want to handle it?
                pass # ignore
            else:
                trees.append(curnode)
    return trees

它运行:
>>> text='''apple: banana eggplant
banana: cantaloupe durian
eggplant:
fig:'''
>>> draw_tree(parser(text))
├─ apple
|  ├─ banana
|  |  ├─ cantaloupe
|  |  └─ durian
|  └─ eggplant
└─ fig

希望它能完全解决您的问题。

更新

我的代码对一些极端情况提供了一些关注,例如:
>>> text='''apple: banana eggplant
banana: cantaloupe durian
eggplant:'''
>>> draw_tree(parser(text))
└─ apple
   ├─ banana
   |  ├─ cantaloupe
   |  └─ durian
   └─ eggplant

请注意apple子节点的最左侧,最后没有|,因为它们被抑制了。

或中间为空:
>>> text='''apple: banana
banana: cantaloupe durian
eggplant:'''
>>> draw_tree(parser(text))
├─ apple
|  └─ banana
|     ├─ cantaloupe
|     └─ durian
└─ eggplant

关于python - 在bash中可视化树,就像unix "tree"的输出一样,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32151776/

10-15 01:12
查看更多