print array contents in variable width columns
I wish to modify my code in such a way that the column widens to accommodate the data.
Below is an example of a broken row
+========+=========+===============+=============+=============+
| Record | Cluster | Current Build | Current Use | Environment |
+--------+---------+---------------+-------------+-------------+
| 3 | 1 | v44 | v44 Live (currently - new company cluster)| PROD |
+--------+---------+---------------+-------------+-------------+
Here is the (kludgy) code I'm using
sub printData {
if (@_) {
# print the data grid top border
printf ("%10s%10s%15s%14s%14s",'+'.('=' x 8).'+',('=' x 9).'+',('=' x 15).'+',('=' x 13).'+',('=' x 13).'+');
print "\n";
# print the data grid column titles
printf ("%-9s%-10s%-16s%-14s%-15s",'| Record ','| Cluster ','| Current Build ','| Current Use ','| Environment |');
print "\n";
# print out each row of data
foreach my $rows (@_) {
# print the data grid demarcation border
printf ("%10s%10s%15s%14s%14s",'+'.('-' x 8).'+',('-' x 9).'+',('-' x 15).'+',('-' x 13).'+',('-' x 13).'+');
print "\n";
开发者_运维问答# print each data cell
printf ("%-9s",'| '.$rows->{'Record ID#'});
printf ("%-10s",'| '.$rows->{'Cluster'});
printf ("%-16s",'| '.$rows->{'Current Build'});
printf ("%-14s",'| '.$rows->{'Current Use'});
# calculate the length of the last column
my $length = length($rows->{'Environment'});
# calculate how many spaces to add to the last column
# the title of this column uses 15 characters (including '|' and spaces)
# we already used three of those spaces for 2 '|' characters and 1 leading space
# so 15 - 3 = 12
# then subtract the length of the return string from 12
my $spaces = 12 - $length;
# we print the last data cell plus the padding spaces calculated above
printf ("%-15s",'| '.$rows->{'Environment'}.(' ' x $spaces).'|');
print "\n";
}
# we print the bottom data grid border
printf ("%10s%10s%15s%14s%14s",'+'.('=' x 8).'+',('=' x 9).'+',('=' x 15).'+',('=' x 13).'+',('=' x 13).'+');
print "\n";
}
else {
if ($debug) {
print "trouble with printData subroutine\n";
}
return 0;
}
}
Text::Table will adjust column widths to fit the data.
You have to pre-scan the data do get the max width of each field, then build your formatting strings.
Text::SimpleTable::AutoWidth is extremely straightforward, and less fiddly than Text::Table.
I'm not familiar with either of the modules already suggested, so if they don't work as you'd like then I'd do as Mouse Food suggested and pre-scan the data to get the maximum width in each column. These maximum widths would then be used in a format string when outputting. If possible it would probably be more efficient to obtain this maximum value while building the array, rather than iterating through it twice at the end.
The code below iterates through the entire array to find the maximum column lengths, but it should be easily adapted if you're calculating it as you go. Also, I've written this off the cuff and haven't tested it, but it should give you the idea.
my %maximums = {
"Record ID#" => 0,
"Cluster" => 0,
"Current Build" => 0,
"Current Use" => 0
};
# calculate the maximum length of the values in each column
foreach my $row (@_) {
foreach my $col (keys %maximums) {
my $col_length = length($row->{$col});
$maximums{key} = $col_length if ($col_length > $maximums{$col});
}
}
# Generate a format string using the maximum column widths. Other format strings
# may be generated in this loop for the other parts of the table. Alternatively
# you could probably transform the one string and replace the characters in it.
my $row_format = "|";
foreach my $col (keys %maximums) {
$row_format .= " %-",$maximums{$key},"s |";
}
$row_format .= "\n";
# Print your headers and borders here, using the other format strings that you
# would calculate above (where $row_format is generated).
# Print each row in the table
foreach my $row (@_) {
printf($row_format, $row->{"Record ID#"}, $row->{"Cluster"},
$row->{"Current Build"}, $row->{"Current Use"});
}
精彩评论