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,您可以调用
来读取该文件。text.txt将存储您提供的文本内容pythonscript.py
#!/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) #"""
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