#!/usr/bin/perl use strict; use warnings; # https://perlmonks.org/?node_id=998803 my $tree = [ [ [[[[["a", "b"], "c"], ["d", "e"]], [[["f", "g"], "h"], [["i", "j"], ["k", ["l", "m"]]]]], ["n", [[["o", "p"], "q"], ["r", "s"]]]], ["t", ["u", "v"]] ], [["w", ["x", "y"]], "z"] ]; $tree = [ [ [[[[["alpha", "bravo"], "charlie"], ["delta", "echo"]], [[["foxtrot", "golf"], "hotel"], [["indigo", "juliet"], ["kilo", ["lima", "mike"]]]]], ["november", [[["oscar", "papa"], "quebec"], ["romeo", "sierra"]]]], ["tango", ["uniform", "victor"]] ], [["whiskey", ["xray", "yankee"]], "zulu"] ]; print tree( $tree ); sub half { ' ' x ( length(shift) >> 1 ) } sub tree { my $tree = shift; ref $tree or return "$tree\n" =~ s/ +/ /gr; # horizontal word ref $tree or return $tree =~ s/./$&\n/gr; # vertical word my ($padl, $padr) = map $_->[0] =~ tr// /cr, # pads my ($left, $right) = map [ tree($_) =~ /.+/g ], @$tree; use List::AllUtils qw( pairwise ); local $_ = join '', pairwise # paste two blocks side by side { "@{[($a // $padl)]} @{[($b // $padr)]}\n" } @$left, @$right; return s{^(?=( *)(\S.*?) {2,}(\S.*?)( *\n))}{ my $span = ' ' x ($+[3] - $-[2] - 2 - length half($2) . half($3)); "$1 " . half($2) . $span =~ tr/ /_/r . half($3) . " $4" . $1 . half($2) . "/$span\\" . half($3) . $4 }er; }