代码之家  ›  专栏  ›  技术社区  ›  LambdaBeta

AWK递归树结构

  •  1
  • LambdaBeta  · 技术社区  · 6 年前

    我试图解析一个文件,它包含层次结构中的行。例如,文件:

    a b c
    a b d
    a B C
    A B C
    

    a 包含 b B 那个 包含 c d 那个 B 包含 C A 包含不同的 B C .

    这很像一个文件列表。

    我想以一种分层次的方式对其进行格式化,如:

    a {
        b {
            c
            d
        }
        B {
            C
        }
    }
    A {
        B {
            C
        }
    }
    

    我想不出一个像样的方法来做这件事。我原以为AWK是我最好的选择,但没想到如何真正实现它。

    上下文

    / . 这些文件是无序的,在编译时通过检查从代码库生成。我想要的输出是一个graphviz点文件,每个文件都包含在它自己的子图中。

    因此,对于输入:

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

    graphviz output

    注意:深度不是固定的,但如果需要,我可以预先计算最大深度。也不是所有的叶子都在同一个深度。

    2 回复  |  直到 6 年前
        1
  •  2
  •   cody    6 年前

    我提供以下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]
        }
      }
    }
    
        2
  •  2
  •   glenn jackman    6 年前

    gawk -F/ '
        {f[$1][$2][$3] = 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]
        }
      }
    }