Indented text converted to arrays of arrays

B

Brad Baxter

Greetings,

I would like to take a table of indented text like the following:

AAA
BBB
CCC
DDD
EEE
FFF
GGG

.... and convert it into a nested array of arrays like the following:

[
[ 'AAA' => [
'BBB',
'CCC',
] ],
[ 'DDD' => [
[ 'EEE' => [
'FFF',
] ],
] ],
'GGG',
]

That is, if an element $a is an array ref, then $a->[0] is the text for
that level and $a->[1] is an array ref to the next level(s). Otherwise $a
is the text for that level.

The indenting is regular, the levels may be arbitrarily deep, and no
double indenting is allowed, i.e., the following is disallowed:

AAA
BBB
CCC
DDD

The solution I've come up with so far is to create the following literal
string and eval it:

[
[ 'AAA' => [
[ 'BBB' => [
] ],
[ 'CCC' => [
] ],
] ],
[ 'DDD' => [
[ 'EEE' => [
[ 'FFF' => [
] ],
] ],
] ],
[ 'GGG' => [
] ],
]

This obviously is not exactly what I describe above, but I can make it
work. However, this solution seems rather draconian, and I feel certain
there is a much simpler answer.

Regards,

Brad
 
B

Brad Baxter

I would like to take a table of indented text like the following:
[...]

I needed help with something quite related to this, but I really don't
know if the answers I got will help you.

You can read the whole thread here:
<http://tinyurl.com/2mb39>

Those answers weren't what I was after, but you inspired me to look
further and I did find an answer here:

http://groups.google.com/[email protected]

By mangling Ben's solution, I got just what I wanted.
I'm a happy camper. :)

Thanks!

Brad


#!/usr/bin/perl
use strict;
use warnings;

use Data::Dumper;
$Data::Dumper::Indent = 1;

print Dumper make_array( <<_end_, " ", 4 );
AAA
BBB
CCC
DDD
EEE
FFF
GGG
_end_

# make_array parameters:
# $raw - string of indented text with newlines
# $char - indent character (typically space or tab)
# $num - number of $char's per indent level

sub make_array {
my( $raw, $char, $num ) = @_;

my @cooked;
my @a = split "\n", $raw;

for my $i ( 0 .. $#a ) {
my( $indent, $string ) = $a[ $i ] =~ /^($char*)(.*)/;
my $len = length( $indent );
my( $lookahead ) = $i == $#a ? '': $a[ $i+1 ] =~ /^($char*)/;
$lookahead = length( $lookahead ) > $len;
my $level = $len/$num;
my $dref = \@cooked;
$dref = $dref->[-1][-1] for 1 .. $level;
push @$dref, $lookahead ? [$string,[]] : $string;
}
return \@cooked;

} # end sub make_array

__END__
$VAR1 = [
[
'AAA',
[
'BBB',
'CCC'
]
],
[
'DDD',
[
[
'EEE',
[
'FFF'
]
]
]
],
'GGG'
];
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top