Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在bash中可视化树,如unix的输出;“树”;_Python_Bash_Tree - Fatal编程技术网

Python 在bash中可视化树,如unix的输出;“树”;

Python 在bash中可视化树,如unix的输出;“树”;,python,bash,tree,Python,Bash,Tree,给定输入: apple: banana eggplant banana: cantaloupe durian eggplant: fig: 我想将其连接成以下格式: ├─ apple │ ├─ banana │ │ ├─ cantaloupe │ │ └─ durian │ └─ eggplant └─ fig 可能有多个根元素,也可能没有多个(在上面的示例中,有两个根元素),我希望找到一个解决方案来处理它们,而不产生任何问题 有没有任何命令行工具可以处理这种转换?如果做不到

给定输入:

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])
它运行:

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

这是另一个版本供你参考

  • 这个版本有一个解析器,但是没有非常健壮的错误检查
  • 根据@hustmphrr的回答,我还更新了代码来处理“空角”和“中间为空”
  • 我还添加了从stdin读取的文件,因此能够与bash脚本集成。您需要取消对最后一部分的注释。假设这个脚本名为script.py,您可以调用
    pythonscript.py
    来读取该文件。text.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
def nx\u ascii\u树(图形,键=无):
"""
创建定向树/林的可打印ascii表示形式。
Args:
图(nx.DiGraph):每个节点最多有一个父节点(
i、 e.图必须是有向林)
键(str):如果指定,则使用此节点属性作为标签,而不是
身份证
参考资料:
https://stackoverflow.com/questions/32151776/visualize-tree-in-bash-like-the-output-of-unix-tree
例子:
>>>将networkx导入为nx
>>>图=nx.dfs_树(nx.balanced_树(2,2),0)
>>>text=nx\u ascii\u树(图形)
>>>打印(文本)
└── 0
├── 1.
│  ├── 3.
│  └── 4.
└── 2.
├── 5.
└── 6.
"""
进口六
将networkx导入为nx
分支机构├─'
烟斗│'
完└─'
破折号─'
断言nx.is_林(图)
断言nx.is_定向(图)
行=[]
def _draw_tree_nx(图形、节点、级别、last=False、sup=[]):
def更新(左,i):
如果i
pprint
将帮助您很好地打印出来。但恐怕不是以这种形式。此表单是固定的还是允许某种形式的灵活性?它不必与上面的表单完全相同,但它应该与Unix
工具使用的样式相匹配(即打印为层次结构)。如果需要的话,Unicode框图形字符可以被标准ASCII字符替换。我只是想了想,我发现这很容易。让我告诉你。我最好如何将上面给出的输入格式解析为Python哈希结构?@CalebXu我不知道您的数据表示。但从你展示的小片段来看,这只是跟踪父对象的问题。表示是问题中提到的第一件事。。。“给定输入”。必须将输入重新格式化为答案中的语法似乎是一个巨大的麻烦。@l'l似乎没有你想象的那么大。@Hustmphrr:也许吧,不过为什么需要添加更多的代码呢?:p修复/更改方面做得很好-与以前的版本+1相比有了极大的改进:)此脚本提供的节点
fig
的输出是
├─ 图
应该在什么时候└─ 图
。通过添加同一级别的检查端来修复该错误
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