So far, by example, you know that the fieldholder
@<<<<
indicates a 5-character,
left-justified field and that
@<<<<<<<<<<
indicates an 11-character, left-justified field. Here’s the
whole scoop, as promised earlier.
Most fieldholders start with
@
. The characters
following the @
indicate the type of field, while
the number of characters (including the @
)
indicates the field width.
If the characters following the @
are
left-angle brackets
(<<<<
), you get a left-justified
field; that is, the value will be padded on the right with spaces if
the value is shorter than the field width. (If a value is too long,
it’s truncated automatically; the layout of the format is
always preserved.)
If the characters following the @
are
right-angle brackets
(>>>>
), you get a right-justified
field—that is, if the value is too short, the field gets padded
on the left with spaces.
Finally, if the characters following the @
are
vertical bars
(||||
), you get a centered field; if the value is
too short, the field gets padded on both sides with spaces, enough on
each side to make the value mostly centered within the field.
Another kind of fieldholder is a
fixed-precision numeric field, useful for those big financial
reports. This field also begins with @
, and is
followed by one or more
#
’s with
an optional dot (indicating a decimal point). Once again, the
@
counts as one of the characters of the field.
For example:
format MONEY = Assets: @#####.## Liabilities: @#####.## Net: @#####.## $assets, $liabilities, $assets-$liabilities .
The three numeric fields allow for six places to the left of the decimal place, and two to the right (useful for dollars and cents). Note the use of an expression in the format—perfectly legal and frequently used.
Perl provides nothing fancier than this; you can’t get floating currency symbols or brackets around negative values or anything interesting. To do so, you have to write your own spiffy subroutine, like so:
format MONEY = Assets: @<<<<<<<<< Liabilities @<<<<<<<< Net: @<<<<<<<<< pretty($assets,10), pretty($liab,9), pretty($assets-$liab,10) . sub pretty { my($n,$width) = @_; $width -= 2; # back off for negative stuff $n = sprintf("%.2f",$n); # sprintf is in later chapter if ($n < 0) { return sprintf("[%$width.2f]", -$n); # negative numbers get brackets } else { return sprintf(" %$width.2f ", $n); # positive numbers get spaces instead } } ## body of program: $assets = 32125.12; $liab = 45212.15; write (MONEY);
As mentioned earlier, Perl normally stops at the first newline of a
value when placing the result into the output. One kind of
fieldholder, the
multiline
fieldholder, allows you to include a value that may have many lines
of information. This fieldholder is denoted by
@*
on a line by
itself; as always, the following line defines the value to be
substituted into the field, which in this case may be an expression
that results in a value containing many
newlines.
The substituted value will look just like the original text: four lines of value become four lines of output. For example:
format STDOUT = Text Before. @* $long_string Text After. . $long_string = "Fred Barney Betty Wilma "; write;
generates the output:
Text Before. Fred Barney Betty Wilma Text After.
Another kind of fieldholder is a filled field. This fieldholder allows you to create a filled paragraph, breaking the text into conveniently sized lines at word boundaries, wrapping the lines as needed. There are a few parts that work together here, but let’s look at them separately.
First, a filled field is denoted by replacing the
@
marker in a text fieldholder with a
caret (so you get
^<<<
, for example). The corresponding
value for a filled field (on the following line of the format)
must be a scalar variable[75] containing text,
rather than an expression that returns a scalar value. The reason for
this is that Perl will alter the variable while filling the filled
field, and it’s pretty hard to alter an expression.
When Perl is filling the filled field, it takes the value of the variable and grabs as many words (using a reasonable definition of “word”)[76] as will fit into the field. These words are actually ripped out of the variable—the value of the variable after filling this field is whatever is left over after removing the words. You’ll see why in a minute.
So far, this isn’t much different from how a normal text field works; we’re printing only as much as will fit (except that we’re respecting a word boundary rather than just cutting it off at the field width). The beauty of this filled field appears when you have multiple references to the same variable in the same format. Take a look at this:
format PEOPLE = Name: @<<<<<<<<<<<<< Comment: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $name, $comment ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $comment ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $comment ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $comment .
Note that the variable $comment
appears four
times. The first line (the one with the $name
field) prints the person’s name and the first few words of the
value in $comment
. But in the process of computing
this line, $comment
is altered so that the words
disappear. The second line once again refers to the same variable
($comment
), and will take the next few words from
the same variable. This process is also used for the third and fourth
lines. Effectively, what we’ve created is a rectangle in the
output that will be filled as best it can with the words from
$comment
spread over four lines.
What happens if the complete text occupies less than four lines? Well, you’ll get a blank line or two. This result is probably OK if you are printing out labels and need exactly the same number of lines for each entry to match them up with the labels. But if you are printing out a report, many blank lines merely use up your printer’s paper budget.
To fix this, use the suppression indicator. Any line that contains a
tilde
(~
) character is suppressed (not output) if the
line would have otherwise printed blank (just whitespace). The tilde
itself always prints as a blank and can be placed anywhere a space
could have been placed in the line. We could rewrite that last
example as follows:
format PEOPLE = Name: @<<<<<<<<<<<<< Comment: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $name, $comment ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $comment ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $comment ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $comment .
Now, if the comment covers only two lines, the third and fourth lines are automatically suppressed.
What if the comment is more than four lines? Well, we could make about 20 copies of the last two lines of that format, hoping that 20 lines will suffice. But that goes against the idea that Perl helps you to be lazy, so there’s a lazy way to do it. Any line that contains two consecutive tildes will be repeated automatically until the result is a completely blank line. (The blank line is suppressed.) This changes our format to look like this:
format PEOPLE = Name: @<<<<<<<<<<<<< Comment: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $name, $comment ~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $comment .
This way, if the comment takes 1 line, 2 lines, or 20 lines, we are still OK.
Note that the criterion for stopping the repeated line requires the line to be blank at some point. That means you probably don’t want any constant text (other than blanks or tildes) on the line, or else the line will never become blank.