📄 ch11.htm
字号:
</TD><TD WIDTH=457>This character indicates that the line should not be written if it is blank.
</TD></TR>
<TR><TD WIDTH=133><CENTER><TT>~~</TT></CENTER>
</TD><TD WIDTH=457>This sequeNCe indicates that lines should be written as needed until the value of a variable is completely written to the output file.
</TD></TR>
<TR><TD WIDTH=133><CENTER><TT>@*</TT></CENTER>
</TD><TD WIDTH=457>This sequeNCe indicates that a multi-line field will be used.
</TD></TR>
</TABLE>
</CENTER>
<P>
<P>
Let's start using some of these formatting characters by formatting
a report to display information about the <TT>FORMAT.DAT</TT>
file we used earlier. The program in Listing 11.4 displays the
information in nice, neat columns.
<P>
<IMG SRC="pseudo.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/pseudo.gif" BORDER=1 ALIGN=RIGHT><p>
<BLOCKQUOTE>
<I>Declare a format for the STDOUT file handle.<BR>
Open the </I><TT><I>FORMAT.DAT</I></TT><I>
file, read all the lines into </I><TT><I>@lines</I></TT><I>,
and then close the file.<BR>
Iterate over the </I><TT><I>@lines</I></TT><I>
array.<BR>
Remove the linefeed character.<BR>
Split the string into three fields.<BR>
If any of the three fields is not present in the line, provide
a default value of an empty string. Notice that a numeric value
must be given to </I><TT><I>$price</I></TT><I>
instead of the empty string.<BR>
Invoke the </I><TT><I>format</I></TT><I>
statement by using the </I><TT><I>write()</I></TT><I>
fuNCtion.</I>
</BLOCKQUOTE>
<HR>
<BLOCKQUOTE>
<B>Listing 11.4 11LST04.PL-Using a Format with <I>STDOUT
<BR>
</I></B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
format =
Album=@<<<<<<<<<<<<< Artist=@>>>>>>>>>>>> Price=$@##.##
$album, $artist, $price
.
open(FILE, "<format.dat");
@lines = <FILE>;
close(FILE);
foreach (@lines) {
chop;
($album, $artist, $price) = (split(/!/));
$album = "" if !defined($album);
$artist = "" if !defined($artist);
$price = 0 if !defined($price);
write();
}
</PRE>
</BLOCKQUOTE>
<HR>
<P>
This program displays the following:
<BLOCKQUOTE>
<PRE>
Album=The Lion King Artist= Price=$ 0.00
Album=Tumbleweed Con Artist= Elton John Price=$123.32
Album=Photographs & Artist= Jim Croce Price=$ 4.95
Album=Heads & Tales Artist= Harry Chapin Price=$ 12.50
</PRE>
</BLOCKQUOTE>
<P>
You can see that the columns are now neatly aligned. This was
done with the format statement and the write() fuNCtion. The format
statement used in this example used three field holders. The first
field holder, @<<<<<<<<<<<<<,
created a left-justified spot for a 14-character-wide field filled
by the value in $album. The second field holder, @>>>>>>>>>>>>,
created a right-justified spot for a 12-character-wide field filled
by the value in $artist. The last field holder, @##.##, created
a six-character-wide field filled by the numeric value in $price.
<P>
You might think it's wasteful to have the field labels repeated
on each line, and I would agree with that. Instead of placing
field labels on the line, you can put them in the report heading.
The next section discusses how to do this.
<H3><A NAME="ExampleReportHeadings">
Example: Report Headings</A></H3>
<P>
<TT>Format</TT> statements for a report
heading use the same format as the detail line <TT>format</TT>
statement, except that <TT>_TOP</TT>
is appended to the file handle. In the case of <TT>STDOUT</TT>,
you must specify <TT>STDOUT_TOP</TT>.
Simply using <TT>_TOP</TT> will not
work.
<P>
To add a heading to the report about the CD collection, you might
use the following <TT>format</TT>
statement:
<BLOCKQUOTE>
<PRE>
format STDOUT_TOP =
@|||||||||||||||||||||||||||||||||||| Pg @<
"CD Collection of David Medinets", $%
Album Artist Price
----------------- ---------------- -------
.
</PRE>
</BLOCKQUOTE>
<P>
Adding this format statement to Listing 11.4 produces this output:
<BLOCKQUOTE>
<PRE>
CD Collection of David Medinets Pg 1
Album Artist Price
----------------- ---------------- -------
The Lion King $ 0.00
Tumbleweed Connec Elton John $123.32
Photographs & Mem Jim Croce $ 4.95
Heads & Tales Harry Chapin $ 12.50
</PRE>
</BLOCKQUOTE>
<P>
Whenever a new page is generated, the heading format is automatically
invoked. Normally, a page is 60 lines long. However, you can change
this by setting the $= special variable.
<P>
Another special variable, $%, holds the current page number. It
will be initialized to zero when your program starts. Then, just
before invoking the heading format, it is iNCremented so its value
is one. You can change $% if you need to change the page number
for some reason.
<P>
You might notice that the | formatting character was used to center
the report title over the columns. You also might notice that
placing the field labels into the heading allows the columns to
be expanded in width.
<P>
Unfortunately, Perl does not truly have any facility for adding
footer detail lines. However, you can try a bit of "magic"
in order to fool Perl into creating footers with static text.
The <TT>$^L</TT> variable holds the
string that Perl writes before every report page except for the
first, and the <TT>$=</TT> variable
holds the number of lines per page. By changing <TT>$^L</TT>
to hold your footer and by reducing the value in <TT>$=</TT>
by the number of lines your footer will need, you can create primitive
footers. Listing 11.5 displays the CD collection report on two
pages by using this technique.
<P>
<IMG SRC="pseudo.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/pseudo.gif" BORDER=1 ALIGN=RIGHT><p>
<BLOCKQUOTE>
<I>Declare a format for the </I><TT><I>STDOUT
</I></TT><I>file handle.<BR>
Declare a heading format for the </I><TT><I>STDOUT
</I></TT><I>file handle.<BR>
Open the </I><TT><I>FORMAT.DAT</I></TT><I>
file, read all the lines into </I><TT><I>@lines</I></TT><I>,
and then close the file.<BR>
Assign a value of </I><TT><I>6</I></TT><I>
to </I><TT><I>$=</I></TT><I>. Normally,
it has a value of </I><TT><I>60</I></TT><I>.
Changing the value to </I><TT><I>6</I></TT><I>
will create very short pages-ideal for small example programs.
<BR>
Assign a string to </I><TT><I>$^L</I></TT><I>,
which usually is equal to the form-feed character. The form-feed
character causes printers to eject a page.<BR>
Iterate over the </I><TT><I>@lines</I></TT><I>
array.<BR>
Remove the linefeed character.<BR>
Split the string into three fields.<BR>
If any of the three fields is not present in the line, provide
a default value of an empty string. Notice that a numeric value
must be given to </I><TT><I>$price</I></TT><I>
instead of the empty string.<BR>
Invoke the </I><TT><I>format</I></TT><I>
statement using the </I><TT><I>write()</I></TT><I>
fuNCtion.<BR>
Print the footer on the last page. You need to explicitly do this
because the last page of the report probably will not be a full
page.</I>
</BLOCKQUOTE>
<HR>
<BLOCKQUOTE>
<B>Listing 11.5 11LST05.PL-Tricking Perl into Creating
Primitive Footers<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
format =
Album=@<<<<<<<<<<<<< Artist=@>>>>>>>>>>>> Price=$@##.##
$album, $artist, $price
.
format STDOUT_TOP =
@|||||||||||||||||||||||||||||||||||| Pg @<
"CD Collection of David Medinets", $%
Album Artist Price
----------------- ---------------- -------
.
open(FILE, "<format.dat");
@lines = <FILE>;
close(FILE);
$= = 6;
$^L = '-' x 60 . "\n" .
"Copyright, 1996, Eclectic Consulting\n" .
"\n\n";
foreach (@lines) {
chop();
($album, $artist, $price) = (split(/!/));
$album = "" if !defined($album);
$artist = "" if !defined($artist);
$price = 0 if !defined($price);
write();
}
print("$^L");
</PRE>
</BLOCKQUOTE>
<HR>
<P>
This program displays the following:
<BLOCKQUOTE>
<PRE>
CD Collection of David Medinets Pg 1
Album Artist Price
----------------- ---------------- -------
Album=The Lion King Artist= Price=$ 0.00
Album=Tumbleweed Con Artist= Elton John Price=$123.32
------------------------------------------------------------
Copyright, 1996, Eclectic Consulting
CD Collection of David Medinets Pg 2
Album Artist Price
----------------- ---------------- -------
Album=Photographs & Artist= Jim Croce Price=$ 4.95
Album=Heads & Tales Artist= Harry Chapin Price=$ 12.50
------------------------------------------------------------
Copyright, 1996, Eclectic Consulting
</PRE>
</BLOCKQUOTE>
<P>
Let me explain the assignment to $^L in more detail. The assignment
is duplicated here for your convenieNCe:
<BLOCKQUOTE>
<PRE>
$^L = '-' x 60 . "\n" .
"Copyright, 1996 by Eclectic Consulting\n" .
"\n\n";
</PRE>
</BLOCKQUOTE>
<P>
The first part of the assignment, '-' x 60, creates a line of
60 dash characters. Then a newline character is coNCatenated to
the line of dashes. Next, the copyright line is appended. Finally,
two more linefeeds are appended to separate the two pages of output.
Normally, you wouldn't add the ending linefeeds because the form-feed
character makes them unnecessary. Here's how the code would look
when designed to be sent to a printer:
<BLOCKQUOTE>
<PRE>
$^L = '-' x 60 . "\n" .
"Copyright, 1996 by Eclectic Consulting" .
"\014";
</PRE>
</BLOCKQUOTE>
<P>
The "\014" string is the equivalent of a form-feed character
because the ASCII value for a form-feed is 12, which is 14 in
octal notation.<BR>
<p>
<CENTER>
<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Note</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
I feel that it's important to say that the coding style in this example is not really recommended for "real" programming. I coNCatenated each footer element separately so I could discuss what each element did. The last three elements in the
footer assignment probably should be placed inside one string literal for efficieNCy.</BLOCKQUOTE>
</TD></TR>
</TABLE>
</CENTER>
<P>
<p>
<CENTER>
<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Tip</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
This example is somewhat iNComplete. If the last page of the report ends at line 20 and there are 55 lines per page, simply printing the <TT>$^L</TT> variable will not place the footer at the bottom of the page. Instead, the footer will appear after line
20. This probably is not the behavior you would like. Try the following statement to fix this problem:
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT>print("\n" x $- . "$^L");</TT>
</BLOCKQUOTE>
<BLOCKQUOTE>
This will coNCatenate enough linefeeds to the beginning of the <TT>footer</TT> variable to place the footer at the bottom of the page.
</BLOCKQUOTE>
</TD></TR>
</TABLE>
</CENTER>
<P>
<H3><A NAME="ExampleUsingFuNCtionsintheValueLine">
Example: Using FuNCtions in the Value Line</A></H3>
<P>
You've already seen the value line in action. Most of the time,
its use will be very simple: create the field holder in the field
line and then put the variable name in the value line. But there
are some other value line capabilities you should know about.
In addition to simple scalar variables, you can specify array
variables and even fuNCtions on the value line. Listing 11.6 shows
a program that uses a fuNCtion to add ellipses to a string if
it is too wide for a column.
<P>
<IMG SRC="pseudo.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/pseudo.gif" BORDER=1 ALIGN=RIGHT><p>
<BLOCKQUOTE>
<I>Declare a format for the </I><TT><I>STDOUT
</I></TT><I>file handle. In this example, the value line
calls the </I><TT><I>dotize()</I></TT><I>
fuNCtion.<BR>
Declare a heading format for the </I><TT><I>STDOUT</I></TT><I>
file handle.<BR>
Declare the </I><TT><I>dotize()</I></TT><I>
fuNCtion.<BR>
Initialize local variables called </I><TT><I>$width</I></TT><I>
and </I><TT><I>$string</I></TT><I>.
<BR>
If the width of </I><TT><I>$string</I></TT><I>
is greater than </I><TT><I>$width</I></TT><I>,
return a value that consists of </I><TT><I>$string</I></TT><I>
shortened to </I><TT><I>$width-3</I></TT><I>
with </I><TT><I>...</I></TT><I> appended
to the end; otherwise, return </I><TT><I>$string</I></TT><I>.
<BR>
Open the </I><TT><I>FORMAT.DAT</I></TT><I>
file, read all the lines into </I><TT><I>@lines</I></TT><I>,
and then close the file.<BR>
Iterate over the </I><TT><I>@lines</I></TT><I>
array.<BR>
Remove the linefeed character.<BR>
Split the string into three fields.<BR>
If any of the three fields is not present in the line, provide
a default value of an empty string. Notice that a numeric value
must be given to </I><TT><I>$price</I></TT><I>
instead of the empty string.<BR>
Invoke the </I><TT><I>format</I></TT><I>
statement by using the </I><TT><I>write()</I></TT><I>
fuNCtion.</I>
</BLOCKQUOTE>
<HR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -