Reputation: 119
F1.txt
tom
x
a=1 b=2 c=3 d=4 e=5
y
b=11 r=12
bob
a=6 b=7 c=8 e=10
result
F2.txt
. X Y
name a b c d e b r
tom 1 2 3 4 5 11 12
bob 6 7 8 - 10 - -
Can you kindly help me in this problem of mine? I have a file F1.txt. My job is to convert that file into a format as shown in example F2.txt. I tried doing this by deleting all string values after Tom and Bob except the numerical values in F1.txt, and then concatenate. Here is the code:
use strict;
open (file100,"< data.txt");
open (file101,">>F3.txt");
my @array = < file100>;
print file101 "name a b c d e\n\n";
print file101 "tom @array[1]\n\n";
print file101 "bob @array[3]\n\n";
Here data.txt:
tom
1 2 3 4 5
bob
6 7 8 10
The output that I am getting with this code is:
F3.txt
name a b c d e
tom 1 2 3 4 5
bob 6 7 8 10
The expected output should be like showed in F2.txt but not like F3.txt
Upvotes: 2
Views: 204
Reputation: 126742
This will do what you ask
use strict;
use warnings;
my %data;
my @names;
while (<DATA>) {
next unless /\S/;
if (/=/) {
%{ $data{$names[-1]} } = /[^\s=]+/g;
}
else {
push @names, /(\S+)/;
}
}
my %keys = map %$_, values %data;
my @keys = sort keys %keys;
printf "%-6s %s\n\n", 'name', join ' ', @keys;
printf "%-6s %s\n\n", $_, join ' ', map $_ // '-', @{$data{$_}}{@keys} for @names;
__DATA__
tom
a=1 b=2 c=3 d=4 e=5
bob
a=6 b=7 c=8 e=10
output
name a b c d e
tom 1 2 3 4 5
bob 6 7 8 - 10
Update
For older versions (before v5.10) Perl will see the defined-or operator //
as a misplaced regular expression match. For these platforms the second printf
statement can be written like this
printf "%-6s %s\n\n", $_, join ' ', map { defined $_ ? $_ : '-' } @{$data{$_}}{@keys} for @names;
Upvotes: 3
Reputation: 1128
#!/usr/bin/env perl
my $pr = "%-12s";
my @headers = qw/name a b c d e/;
my %names;
while (<DATA>) {
chomp;
s/^\s+//g;
s/\s+$//g;
my $line = <DATA>;
$line =~ s/^\s+//g;
$line =~ s/\s+$//g;
%{$names{$_}} = split /\s*=\s*|\s+/, $line;
}
printf $pr x @headers . "\n", @headers;
for (keys %names) {
my @ds = ($_);
for my $k (@headers[1..$#headers])
{
my $v = $names{$_}->{$k};
push @ds, $v ? $v : '-';
}
printf $pr x @ds . "\n", @ds;
}
__DATA__
tom
a = 10.1 b = 2 c = 300.89 d=4145 e=55
bobby
a= 60 b = 74.2 c = 8 e = 10.25
output:
name a b c d e
tom 1 2 3 4 5
bob 6 7 8 - 10
Upvotes: 4
Reputation: 2277
For your understanding I am taking a long cut with this:
use strict;
use warnings;
my %hash;
my @vals;
my $key;
my $val;
my $name;
my @headings;
my $file100;
open ($file100, "<", "data.txt");
while (<$file100>)
{
chomp;
next if (! m/\S/);
if (m/=/)
{
@vals = $_ =~ /(.+)=(.+)\b/g;
while (@vals)
{
$key = shift @vals;
if (!grep(/^$key$/, @headings))
{
push (@headings, $key);
}
$val = shift @vals;
$hash{$name}{$key} = $val;
}
} else {
$name = $_;
}
print "name\t" . join ("\t", @headings) . "\n\n";
for my $key1 (keys %hash)
{
print $key1;
for (@headings)
{
if (defined $hash{$key1}{$_})
{
print "\t" . $hash{$key1}{$_};
} else
{
print "\t-";
}
}
print "\n\n";
}
You need to pick up a Perl book and study it.
Upvotes: 1