AWK递归树结构
AWK recursive tree structure
我正在尝试解析包含分层结构中的行的文件。例如文件:
a b c
a b d
a B C
A B C
表示a
包含b
和B
,表示b
包含c
和d
,表示B
包含 C
。 A
包含不同的 B
,后者包含自己的 C
。
这很像一个文件列表。
我想以分层括号的方式对其进行格式化,例如:
a {
b {
c
d
}
B {
C
}
}
A {
B {
C
}
}
我想不出一个合适的方法来做到这一点。我认为 AWK 是我最好的选择,但我想不出如何实际实施它。
上下文
我的输入实际上是一个文件列表。如果需要,我当然可以用空格分隔字段,或者用 /
保留它们。这些文件是无序的,是在编译时通过检查从代码库生成的。我想要的输出将是一个 graphviz DOT 文件,其中包含每个文件在其自己的子图中。
因此对于输入:
a/b/c
a/b/d
a/B/C
A/B/C
输出将是
digraph {
subgraph cluster_a {
label = a
subgraph cluster_b {
label = b
node_1 [label=c]
node_2 [label=d]
}
subgraph cluster_B {
label = B
node_3 [label=C]
}
}
subgraph cluster_A {
label = A
subgraph cluster_B {
label = B
node_4 [label=C]
}
}
}
有人知道我怎样才能完成这个处理吗?我也对其他工具持开放态度,而不仅仅是 AWK。
注意:深度不是固定的,但如有必要,我可以预先计算最大深度。也不是所有的叶子都处于相同的深度。
如果深度固定在3层
gawk -F/ '
{f[][][] = 1}
END {
n = 0
print "digraph {"
for (a in f) {
print " subgraph cluster_" a " {"
print " label = " a
for (b in f[a]) {
print " subgraph cluster_" b " {"
print " label = " b
for (c in f[a][b]) {
printf " node_%d [label=%s]\n", ++n, c
}
print " }"
}
print " }"
}
print "}"
}
' file
digraph {
subgraph cluster_A {
label = A
subgraph cluster_B {
label = B
node_1 [label=C]
}
}
subgraph cluster_a {
label = a
subgraph cluster_B {
label = B
node_2 [label=C]
}
subgraph cluster_b {
label = b
node_3 [label=c]
node_4 [label=d]
}
}
}
如果深度是任意的,事情就会变得复杂。
I'm open to other tools as well, not just AWK.
我提供这个Python解决方案:
import sys
INDENT = ' '
NODE_COUNT = 1
def build(node, l):
x = l[0]
if x not in node:
node[x] = {}
if len(l) > 1:
build(node[x], l[1:])
def indent(s, depth):
print('%s%s' % (INDENT * depth, s))
def print_node(label, value, depth):
if len(value.keys()) > 0:
indent('subgraph cluster_%s {' % label, depth)
indent(' label = %s' % label, depth)
for child in value:
print_node(child, value[child], depth+1)
indent('}', depth)
else:
global NODE_COUNT
indent('node_%d [label=%s]' % (NODE_COUNT, label), depth)
NODE_COUNT += 1
def main():
d = {}
for line in sys.stdin:
build(d, [x.strip() for x in line.split()])
print('digraph {')
for k in d.keys():
print_node(k, d[k], 1)
print('}')
if __name__ == '__main__':
main()
结果:
$ cat rels.txt
a b c
a b d
a B C
A B C
$ cat rels.txt | python3 make_rels.py
digraph {
subgraph cluster_a {
label = a
subgraph cluster_b {
label = b
node_1 [label=c]
node_2 [label=d]
}
subgraph cluster_B {
label = B
node_3 [label=C]
}
}
subgraph cluster_A {
label = A
subgraph cluster_B {
label = B
node_4 [label=C]
}
}
}
我正在尝试解析包含分层结构中的行的文件。例如文件:
a b c
a b d
a B C
A B C
表示a
包含b
和B
,表示b
包含c
和d
,表示B
包含 C
。 A
包含不同的 B
,后者包含自己的 C
。
这很像一个文件列表。
我想以分层括号的方式对其进行格式化,例如:
a {
b {
c
d
}
B {
C
}
}
A {
B {
C
}
}
我想不出一个合适的方法来做到这一点。我认为 AWK 是我最好的选择,但我想不出如何实际实施它。
上下文
我的输入实际上是一个文件列表。如果需要,我当然可以用空格分隔字段,或者用 /
保留它们。这些文件是无序的,是在编译时通过检查从代码库生成的。我想要的输出将是一个 graphviz DOT 文件,其中包含每个文件在其自己的子图中。
因此对于输入:
a/b/c
a/b/d
a/B/C
A/B/C
输出将是
digraph {
subgraph cluster_a {
label = a
subgraph cluster_b {
label = b
node_1 [label=c]
node_2 [label=d]
}
subgraph cluster_B {
label = B
node_3 [label=C]
}
}
subgraph cluster_A {
label = A
subgraph cluster_B {
label = B
node_4 [label=C]
}
}
}
有人知道我怎样才能完成这个处理吗?我也对其他工具持开放态度,而不仅仅是 AWK。
注意:深度不是固定的,但如有必要,我可以预先计算最大深度。也不是所有的叶子都处于相同的深度。
如果深度固定在3层
gawk -F/ '
{f[][][] = 1}
END {
n = 0
print "digraph {"
for (a in f) {
print " subgraph cluster_" a " {"
print " label = " a
for (b in f[a]) {
print " subgraph cluster_" b " {"
print " label = " b
for (c in f[a][b]) {
printf " node_%d [label=%s]\n", ++n, c
}
print " }"
}
print " }"
}
print "}"
}
' file
digraph {
subgraph cluster_A {
label = A
subgraph cluster_B {
label = B
node_1 [label=C]
}
}
subgraph cluster_a {
label = a
subgraph cluster_B {
label = B
node_2 [label=C]
}
subgraph cluster_b {
label = b
node_3 [label=c]
node_4 [label=d]
}
}
}
如果深度是任意的,事情就会变得复杂。
I'm open to other tools as well, not just AWK.
我提供这个Python解决方案:
import sys
INDENT = ' '
NODE_COUNT = 1
def build(node, l):
x = l[0]
if x not in node:
node[x] = {}
if len(l) > 1:
build(node[x], l[1:])
def indent(s, depth):
print('%s%s' % (INDENT * depth, s))
def print_node(label, value, depth):
if len(value.keys()) > 0:
indent('subgraph cluster_%s {' % label, depth)
indent(' label = %s' % label, depth)
for child in value:
print_node(child, value[child], depth+1)
indent('}', depth)
else:
global NODE_COUNT
indent('node_%d [label=%s]' % (NODE_COUNT, label), depth)
NODE_COUNT += 1
def main():
d = {}
for line in sys.stdin:
build(d, [x.strip() for x in line.split()])
print('digraph {')
for k in d.keys():
print_node(k, d[k], 1)
print('}')
if __name__ == '__main__':
main()
结果:
$ cat rels.txt
a b c
a b d
a B C
A B C
$ cat rels.txt | python3 make_rels.py
digraph {
subgraph cluster_a {
label = a
subgraph cluster_b {
label = b
node_1 [label=c]
node_2 [label=d]
}
subgraph cluster_B {
label = B
node_3 [label=C]
}
}
subgraph cluster_A {
label = A
subgraph cluster_B {
label = B
node_4 [label=C]
}
}
}