可视化bash中的树,就像UNIX“tree”命令的输出一样。

2024-10-08 22:21:39 发布

您现在位置:Python中文网/ 问答频道 /正文

给定输入:

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

我想把它连接成以下格式:

^{pr2}$

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

有没有可以处理这种转换的命令行工具?如果做不到这一点,在其他脚本语言中是否有什么东西可以稍微轻松地处理这个问题(我已经看过Python的pprint,但我也不确定如何使用它来处理类似的问题)?在


Tags: 工具命令行元素示例apple格式fig解决方案
3条回答

这是另一个版本供你参考。在

  • 这个版本有一个解析器,但是没有非常健壮的错误检查。在
  • 基于@hustmphrr的回答,我还更新了代码来处理“空角”和“中间空壳”
  • 我还从stdin添加了read文件,从而能够与bash脚本集成。你需要取消最后一部分的注释。假设这个脚本被称为脚本.py,您可以调用python script.py < test.txt来读取文件。这个文本.txt将存储您提供的文本内容。在

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import sys
    input_str = """apple: banana eggplant
    banana: cantaloupe durian
    eggplant:
    fig:
    """
    leaf_end_str = '└─ '
    leaf_inner_str = '├─ '
    child_conn_str = '│  '
    empty_str = '   '
    
    #debug = True
    debug = False
    
    def recursive_print(cur_root, p2r_list, prefix, is_end=False, only_one=False):
        # first print current node
        if only_one or is_end:
            print '%s%s%s'%(prefix, leaf_end_str, cur_root)
        else:
            print '%s%s%s'%(prefix, leaf_inner_str, cur_root)
    
        if only_one == True:
            next_prefix = prefix + empty_str
        else:
            next_prefix = prefix + child_conn_str
    
        #print p2r_list[cur_root]
        if p2r_list.has_key(cur_root):
            next_only_one = ( len(p2r_list[cur_root]) == 1 )
            for child in p2r_list[cur_root]:
                next_is_end = (child == p2r_list[cur_root][-1] )
                recursive_print(child, p2r_list, next_prefix, is_end = next_is_end, only_one = next_only_one)
    
    def tree_print(content):
        # get root and parent-children relation
        root = {} # check whether a node is root
        p2r_list = {} # store the parent-child relation
        for line in content.split('\n'):
            line = line.strip()
            if line == "":
                continue
    
            ws = line.split(':') # separate parent and child
            if not root.has_key(ws[0]):
                root[ws[0]] = True
            if not p2r_list.has_key(ws[0]):
                p2r_list[ws[0]] = []
            if len(ws) > 1:
                for child in ws[1].strip().split(' '):
                    if child == '':
                        continue
                    root[child] = False
                    p2r_list[ws[0]].append(child)
    
        if debug:
            print root, '\n', p2r_list
    
        root_list = [r for r in root.keys() if root[r]]
        for r in root_list:
            if r == root_list[-1]:
                recursive_print(r, p2r_list, '', is_end = True, only_one=True)
            else:
                recursive_print(r, p2r_list,'')
    
    if __name__ == "__main__":
        tree_print(input_str )
        """
        content = sys.stdin.read()
        #print content
        if content != '':
            tree_print( content)
        #"""
    

这个问题很古老,但这里是第一个解决方案的networkx版本:

def nx_ascii_tree(graph, key=None):
    """
    Creates an printable ascii representation of a directed tree / forest.

    Args:
        graph (nx.DiGraph): each node has at most one parent (
            i.e. graph must be a directed forest)
        key (str): if specified, uses this node attribute as a label instead of
            the id

    References:
        https://stackoverflow.com/questions/32151776/visualize-tree-in-bash-like-the-output-of-unix-tree

    Example:
        >>> import networkx as nx
        >>> graph = nx.dfs_tree(nx.balanced_tree(2, 2), 0)
        >>> text = nx_ascii_tree(graph)
        >>> print(text)
        └── 0
           ├── 1
           │  ├── 3
           │  └── 4
           └── 2
              ├── 5
              └── 6
    """
    import six
    import networkx as nx
    branch = '├─'
    pipe = '│'
    end = '└─'
    dash = '─'

    assert nx.is_forest(graph)
    assert nx.is_directed(graph)

    lines = []

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

        initial = ['{}  '.format(pipe)] * level
        parts = six.moves.reduce(update, sup, initial)
        prefix = ''.join(parts)
        if key is None:
            node_label = str(node)
        else:
            node_label = str(graph.nodes[node]['label'])

        suffix = '{} '.format(dash) + node_label
        if last:
            line = prefix + end + suffix
        else:
            line = prefix + branch + suffix
        lines.append(line)

        children = list(graph.succ[node])
        if children:
            level += 1
            for node in children[:-1]:
                _draw_tree_nx(graph, node, level, sup=sup)
            _draw_tree_nx(graph, children[-1], level, True, [level] + sup)

    def draw_tree(graph):
        source_nodes = [n for n in graph.nodes if graph.in_degree[n] == 0]
        if source_nodes:
            level = 0
            for node in source_nodes[:-1]:
                _draw_tree_nx(graph, node, level, last=False, sup=[])
            _draw_tree_nx(graph, source_nodes[-1], level, last=True, sup=[0])

    draw_tree(graph)
    text = '\n'.join(lines)
    return text

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

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])

它要求你用给定的形式表示数据。在


关于数据反序列化,您只需要跟踪父节点,这样当叶看起来是节点时,只需替换它:

^{pr2}$

它运行:

>>> 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

相关问题 更多 >

    热门问题