Paul Nathan
Paul Nathan

Reputation: 40299

How can I format columns without using Perl's format?

Often in Perl I want to print out column/row data, say, from a hash.

This is simple:

foreach my $k(keys %h)
{
  print $k, "\t", $h{$k}, "\n";
}

However, if the key happens to have a varying length, then the formatting just looks very jagged. I've investigated format, and it's typically too heavyweight for what I'm looking for, which is a 'simple' column-row aligning pretty-printer.

Upvotes: 2

Views: 3584

Answers (6)

Shez
Shez

Reputation: 87

I know you said format might be too heavy-weight, but it might actually be less complex. Try something like this:

foreach my $k(keys %h) {
  format =
  Key:  @<<<<<<<<<<<<<<<< Value:  @>>>>>>>>>>>>>>>>>
  $k,                     $h{$k}
  .

  write;
}

Upvotes: 1

Aquatoad
Aquatoad

Reputation: 788

It is probably not an optimal solution, but you'll need to find your maximum key and maximum value lengths, and then pass them to either sprintf() or pack().

Or you could use static maximum lengths if your data source has "reasonable" constraints (for example, column length limits in a database, etc.)

Upvotes: 3

Ivan Nevostruev
Ivan Nevostruev

Reputation: 28713

I think you'll find printf useful. Here is a small example:

printf("%10s\t%10s\n", $k, $h{$k});
## prints "         key\t         value\n"
## prints "  longer_key\t  longer_value\n"

Long values are not truncated, and you can change text alignment inside the block:

  • %10s - means string type of length 10 (left aligned)
  • %-10s - means string type of length 10 (right aligned)

A full list of formats is on the sprintf man page.

Upvotes: 16

Ether
Ether

Reputation: 53966

Check out the x operator (documented at perldoc perlop), useful for simple formatting tasks that involve padding fields to a specific length:

while ((my $key, $value) = each %h)
{
    print $key . (" " x (20 - length $key)) . $value, "\n";
}

You can also use sprintf or printf (perldoc -f sprintf, perldoc -f printf) (with these you can also pad with zeros in numbers):

while ((my $key, $value) = each %h)
{
    printf("%20s %20s\n", $key, $value);
}

Upvotes: 7

Michael Carman
Michael Carman

Reputation: 30831

The robust solution requires two passes: one to determine the length of the longest key, the other to print the output:

my $l = 0;
foreach my $key (keys %hash) {
    $l = length($key) if length($key) > $l;
}

foreach my $key (keys %hash) {
    printf "%-${l}s  %s\n", $key, $hash{$key};
}

If you know the upper limit of the key lengths ahead of time, you can avoid the first loop.

Upvotes: 6

user181548
user181548

Reputation:

If you want a heavy-duty solution, there are modules like Text::Table.

Upvotes: 5

Related Questions