vnpenguin has asked for the wisdom of the Perl Monks concerning the following question:

Hi all, I have a text file :
v_x { x1 x2 x3 x4 x5 x6 x7 x8 } v_y { y1 y2 y3 y4 y5 } v_z { z1 z2 z3 z4 z5 z6 } ...
There are about 100 "vectors" with different length. I would like to write a Perl script to convert it to the form:
x1 y1 z1 x2 y2 z2 x3 y3 z3 x4 y4 z4 x5 y5 z5 x6 z6 x7 x8
So each vector becomes a column. Because of different length of vector, I don't know how to process it. In this case, using of Array or Hash is better ? Could you give me some ideas please. Thank you in advance, Regards,

2005-12-15 Retitled by planetscape, as per Monastery guidelines
Original title: 'Text processing'

Replies are listed 'Best First'.
Re: text processing - convert list of vectors to tabular format
by gopalr (Priest) on Dec 15, 2005 at 09:29 UTC

    Hi vnpenguin,

    Use each_array method in List::MoreUtils module.

    use strict; use List::MoreUtils qw(each_array); undef $/; my $text=<DATA>; my $a=$1 if $text=~m#v_x \{([^\}]+)\}#; my @a=split( "\n", $a ); my $b=$1 if $text=~m#v_y \{([^\}]+)\}#; my @b=split( "\n", $b ); my $c=$1 if $text=~m#v_z \{([^\}]+)\}#; my @c=split( "\n", $c ); my $ea = each_array(@a, @b, @c); while ( my ($a, $b, $c) = $ea->() ) { print "$a\t$b\t$c\n"; } __DATA__ v_x { x1 x2 x3 x4 x5 x6 x7 x8 } v_y { y1 y2 y3 y4 y5 } v_z { z1 z2 z3 z4 z5 z6 }

    OUTPUT:

    x1 y1 z1 x2 y2 z2 x3 y3 z3 x4 y4 z4 x5 y5 z5 x6 z6 x7 x8

    Thanks,
    Gopal.R

      Hi Gopal.R, Thank you so much for your reply. Regards,
Re: text processing - convert list of vectors to tabular format
by secret (Beadle) on Dec 15, 2005 at 09:32 UTC
    Here's a simple solution with an hash of array . There might be a better way, tho ...
    use strict ; use warnings ; my $vec ; my %rez ; my $cpt = 0 ; my $maxcpt = 0; foreach my $item (<DATA>) { chomp $item ; next if $item =~ m/^}$/ ; if ( $item =~ m/^v_(.*) {/ ) { $vec = $1 ; $maxcpt = $cpt if $cpt > $maxcpt ; $cpt = 0 ; } else { $rez{$vec}[$cpt] = $item ; $cpt ++ ; } } foreach my $cpt (0..$maxcpt) { foreach my $vec ( keys %rez ) { if (defined $rez{$vec}[$cpt]) { print $rez{$vec}[$cpt], "\t" } else { print "\t" } ; } print "\n" } __DATA__ v_x { x1 x2 x3 x4 x5 x6 x7 x8 } v_y { y1 y2 y3 y4 y5 } v_z { z1 z2 z3 z4 z5 z6 }
      Thank you very much, Regards,
Re: text processing - convert list of vectors to tabular format
by tphyahoo (Vicar) on Dec 15, 2005 at 15:20 UTC
    I rather like this, because I think it is simple to understand and would be easy to maintain:
    use strict; use warnings; my ($x, $y) = (0,0); #table axes, x is horizontal, y is vertical my ($max_x, $max_y) = (0,0); my $table ; #hash of arrays while (<DATA>) { chomp; #print "$_\n"; if ( $_ =~ m/^v_(.*)\s*{/ ) { $y = 0; } elsif ( $_ =~ m/^}$/ ) { $max_x = $x if $x++ > $max_x; } else { $table->[$x]->[$y] = $_; $max_y = $y if $y++ > $max_y; } } for my $y (0..$max_y) { for my $x (0..$max_x) { my $item = defined( $table->[$x]->[$y] ) ? $table->[$x]->[$y] +: ' '; print "$item "; } print "\n"; } __DATA__ v_x { x1 x2 x3 x4 x5 x6 x7 x8 } v_y { y1 y2 y3 y4 y5 } v_z { z1 z2 z3 z4 z5 z6 }
      Hi tphyahoo, There is an extra empty ligne in output :) So maybe:
      for my $y (0..$max_y-1) { ... }
      Thank you !
Re: text processing - convert list of vectors to tabular format
by jdporter (Paladin) on Dec 15, 2005 at 16:15 UTC

    This problem is interesting (i.e. fun) because it has two parts, each of which requires some thought: parsing the input data and formatting the output.
    Here's my solution:

    use strict; my @keys; # just to preserve order my %data; local $_ = do { local $/; <DATA> }; while ( /(v_\w) {\n([^}]*)\n}/g ) { push @keys, $1; $data{$1} = [ split /\n/, $2 ]; } my $row = 0; while (1) { my @v = map { $data{$_}[$row] } @keys; last unless grep defined($_), @v; printf "%-3s", $_ for @v; print "\n"; $row++; }
    We're building the house of the future together.
Re: text processing - convert list of vectors to tabular format
by kulls (Hermit) on Dec 15, 2005 at 09:50 UTC
    similar node,
    perhaps you can check this node for more info.
    -kulls
Re: text processing - convert list of vectors to tabular format
by pKai (Priest) on Dec 15, 2005 at 17:04 UTC
    Having asked myself how to involve Perl's range operator, I came up with the following

    use strict; use warnings; $\ = $/; while (<DATA>) { chomp; my $v= ((/{/ .. /}/) || 0); if ($v==1) { @_=(); } elsif ($v=~/E0$/) { print "@_"; } else { push @_, $_; } }
    Edit: Hm, somewhat inchoate, since it doesn't address the OP's requirement to transpose the result.

    You can use the above with

    push @collect, [@_];

    instead of the print statement (declare @collect prior to the loop) and use any suggested method here or in the other mentioned thread to transpose and output that AoA.

Re: text processing - convert list of vectors to tabular format
by Mandrake (Chaplain) on Dec 15, 2005 at 17:47 UTC
    Another one.
    use strict; undef $/; my $data = <DATA>; my (%hash, @chars) ; my $count = 0; foreach (split("\n", $data)) { push @chars , $1 if $_ =~ m/^v_((.*)) {/ ; # Thanks Anonymous Monk-- } foreach (@chars) { @{$hash{$_}} = split( "\n", $1) if $data =~ m#v_$_ \{([^\}]+)\}#; $count = ($count > @{$hash{$_}}) ? $count : @{$hash{$_}} ; } for my $c (0..$count) { print ${@{$hash{$_}}}[$c] ."\t" foreach ( @chars ); print "\n" ; }
    Thanks..
      Why do you split $1 on "{"? $1 does never contain a "{". Or am I mistaken?