user1487189
user1487189

Reputation:

How to format output in Perl?

I have a Perl code responsible for formatting output. Problem is I need to calculate correct number of tabs to be put before one particular character in each string (let's say it's /). So instead of getting lines with different lengths I'd like to get fixed-length strings (but as short as possible, using the longest as max). How should I approach this?

Example of output (with format commented out, just raw array):

Long title with some looong words / short text
Another title / another short text

I need it like this:

title with some looong words / short text
Different title              / another short text

This was my first attempt, but it didn't involve using tabs after one particular character.

my $text = Text::Format->new;

$text->rightAlign(1);
$text->columns(65);
$text->tabstop(4);

$values[$i] = $text->format(@values[$i]);

Upvotes: 2

Views: 3690

Answers (3)

David W.
David W.

Reputation: 107040

There are two generally accepted ways to format text in Perl, so columns line up:

  • Use printf and sprintf. This is probably the most common way it's done.
  • Use Perl Format capabilities. You define what you want a line to look like, then use write to print to that format.

I haven't seen people use Perl Format specifications stuff in years. It was a big feature back in Perl 3.x heydays because Perl was mainly used as a super-awk replacement language(Practical Extraction and Reporting Language). However, the mechanism is still there, and I'm sure it'll be fun to learn.


Now comes the second part of your query. You really don't merely want the text to be formatted, you want it to be formatted with tabs.

Fortunately, Perl has a built in module called Text::Tabs. It's one of those modules that does one or two obscure tasks, but does them well.

Actually, Text::Tabs doesn't handle the two tasks it does well, but adequately.

Produce your report using sprintf or the build in Perl formatting capabilities. Save your whole report in an array. It has to be an array because Text::Tabs doesn't handle NLs. Then use the unexpand function to replace spaces in that array into another array with tabs.

WORD 'O WARNING: Text::Tabs does something very naughty: It imports the variable $tabstop into your program without asking your permission. If you use a variable called $tabstop, you'll have to change it. You can set $tabstop to be the number of spaces a tab represents. It's set to 8 as a default.

Upvotes: 2

Michael Carman
Michael Carman

Reputation: 30831

From what I can find in the documentation Text::Format only does paragraph formatting. What you want is a tabular format. The basic approach to that is to split your data into a matrix of text for each row & column, find the longest element for each column, and use that to output fixed width data. e.g.:

my @values = (
    'Long title with some looong words / short text',
    'Another title / another short text',
);

# split values into per-column text
my @text = map { [ split '\s*(/)\s*', $_ ] } @values;

# find the maximum width of each column
my @width;
foreach my $line (@text) {
    for my $i (0 .. $#$line) {
        no warnings 'uninitialized';
        my $l = length $line->[$i];
        $width[$i] = $l if $l > $width[$i];
    }
}

# build a format string using column widths
my $format = join ' ', map { "%-${_}s" } @width;
$format .= "\n";

# print output in columns
printf $format, @$_ foreach @text;

This produces the following:

Long title with some looong words / short text        
Another title                     / another short text

Upvotes: 0

choroba
choroba

Reputation: 241868

The module Text::Table might help you.

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

use Text::Table;

my @array = ('Long title with some looong words', 'short text',
             'Another title',                     'another short text');

my $table = Text::Table::->new(q(), \' / ', q()); # Define the separator.
$table->add(shift @array, shift @array) while @array;
print $table;

Upvotes: 0

Related Questions