Perl: Reports

Reports

Table of Contents:

  • Format Statements
  • Field Lines
  • Report Headings

Reports

Perl has a few special features that let you create simple reports. The reports can have a header area where you can place a title, page number, and other information that stays the same from one page to the next. Perl will track how many lines have been used in the report and automatically generate new pages as needed.

Compared to learning about regular expressions, learning how to create reports will be a breeze. There are only a few tricky parts

Let\'s start out by using the print() function to display a CD collection and then gradually moves from displaying the data to a fully formatted report.

The data file shown below is used for all of the examples in this chapter. The format is pretty simple:

  • the CD album\'s title,
  • the artist\'s name, and
  • the album\'s price.
  • each line ia file contains the three fields separted by a !. Any charatcer could actually be used.

The file is as follows:

Love Supreme!
A Kind of Blue!Miles Davis!9.99
Koln Concert!Keith Jarrett!15.99
Birds of Fire!Mahavishnu Orchestra!10.99

You\'ll find that Perl is very handy for small text-based data files like this. You can create them in any editor and use any field delimiter you like.

Now that we have some data, let\'s look at a program (report1.pl) that reads the data file and displays the information:

open(FILE, "
@lines = ;
close(FILE);

foreach (@lines) {
chop;
($album, $artist, $price) = (split(/!/));
print("Album=$album Artist=$artist Price=$price\n");
}

This program displays:

Use of uninitialized value at report1.pl line 8.
Album = Love Supreme Artist = Price =
Album = A Kind of Blue Artist = Miles Davis Price = 9.99
Album = Koln Concert Artist = Keith Jarrett Price = 15.99
Album = Birds of Fire Artist = Mahavishnu Orchestra Price = 10.99

Why is an error being displayed on the first line of the output? If you said that the split() function was returning the undefined value when there was no matching field in the input file, you were correct. The first input line was the following:

A Love Supreme!

There are no entries for the Artist or Price fields. Therefore, the $artist and $price variables were assigned the undefined value, which resulted in Perl complaining about uninitialized values. You can avoid this problem by assigning the empty string to any variable that has the undefined value. To do this report2.pl:

open(FILE, "

@lines = ;

close(FILE);


foreach (@lines) {

chop;

($album, $artist, $price) = (split(/!/));

$album = "" if !defined($album); These lines assign null

$artist = "" if !defined($artist); strings if no info is

$price = "" if !defined($price); present in the record.

print("Album=$album Artist=$artist Price=$price\n");

}

The first four lines this program displays are the following:

Album=A Love Supreme   Artist=                      Price=
Album=A Kind of Blue Artist=Miles Davis Price=9.99
Album=Koln Concert Artist=Keith Jarrett Price=15.99
Album=Birds of Fire Artist=Mahvishnu Orchestra Price=10.99

The error has been eliminated, but it is still very hard to read the output because the columns are not aligned. The rest of this chapter is devoted to turning this jumbled output into a report.

Perl reports have heading and have detail lines. A heading is used to identify the report title, the page number, the date, and any other information that needs to appear at the top of each page. Detail lines are used to show information about each record in the report. In the data file being used for the examples in this chapter , each CD has its own detail line.

Headings and detail lines are defined by using format statements, which are discussed in the next section.

Format Statements

Perl uses formats as guidelines when writing report information. A format is used to tell Perl what static text is needed and where variable information should be placed. Formats are defined by using the format statement. The syntax for the format statement is format

format FORMATNAME =

FIELD_LINE

VALUE_LINE

The FORMATNAME is usually the same name as the file handle that is used to accept the report output.

If you don\'t specify a FORMATNAME, Perl uses STDOUT. The FIELD_LINE part of the format statement consists of text and field holders. A field holder represents a given line width that Perl will fill with the value of a variable. The VALUE_LINE line consists of a comma-delimited list of expressions used to fill the field holders in FIELD_LINE.

Report headings, which appear at the top of each page, have the following format: format

FORMATNAME_TOP =
FIELD_LINE
VALUE_LINE

Yes, the only difference between a detail line and a heading is that _TOP is appended to the FORMATNAME.

NoteThe location of format statements is unimportant because they define only a format and never are executed. I feel that they should appear either at the beginning of a program or the end of a program, rarely in the middle. Placing format statements in the middle of your program might make them hard to find when they need to be changed. Of course, you should be consistent where you place them.

A typical format statement might look like this:

format =

The total amount is $@###.##

$total

The at character @ is used to start a field holder. In this example, the field holder is seven characters long (the at sign and decimal point count, as well as the pound signs #). The next section, "Example: Using Field Lines," goes into more detail about field lines and field holders.

Format statements are used only when invoked by the write() function. The write() function takes only one parameter: a file handle to send output to. Like many things in Perl, if no parameter is specified, a default is provided. In this case, STDOUT will be used when no FORMATNAME is specified. In order to use the preceding format, you simply assign a value to $total and then call the write() function. For example (total.pl):

$total = 243.45

write();

$total = 50.00

write();

These lines will display:

    The total amount is $  243.45

The total amount is $ 50.50

The output will be sent to STDOUT. Notice that the decimal points are automatically lined up when the lines are displayed.

Field Lines

The field lines of a format statement control what is displayed and how. The simplest field line contains only static text. You can use static or unchanging text as labels for variable information, dollar signs in front of amounts, a separator character such as a comma between first and last name, or whatever else is needed. However, you\'ll rarely use just static text in your format statement. Most likely, you\'ll use a mix of static text and field holders.

You saw a field holder in action in the last section in which I demonstrated sending the report to STDOUT. I\'ll repeat the format statement here so you can look at it in more detail:

format =

The total amount is $@###.##

$total

The character sequence The total amount is $ is static text. It will not change no matter how many times the report is printed. The character sequence @###.##, however, is a field holder. It reserves seven spaces in the line for a number to be inserted. The third line is the value line; it tells Perl which variable to use with the field holder.

The following format characters can be uses in field lines.

  • @ -- This character represents the start of a field holder.
  • < -- This character indicates that the field should be left-justified.
  • > -- This character indicates that the field should be right-justified.

    | -- This character indicates that the field should be centered.

    # -- This character indicates that the field will be numeric. If used as the first character in the line, it indicates that the entire line is a comment.

  • . -- This character indicates that a decimal point should be used with numeric fields.
  • ^ -- This character also represents the start of a field holder. Moreover, it tells Perl to turn on word-wrap mode.
  • ~ -- This character indicates that the line should not be written if it is blank.
  • ~~-- This sequence indicates that lines should be written as needed until the value of a variable is completely written to the output file.
  • @* -- This sequence indicates that a multi-line field will be used.

Let\'s start using some of these formatting characters by formatting a report to display information about the FORMAT.DAT file we used earlier.

We will display the information in nice, neat columns. as follows:

  • Declare a format for the STDOUT file handle.
  • Open the FORMAT.DAT file, read all the lines into @lines, and then close the file.
  • Iterate over the @lines array.
  • Remove the linefeed character.
  • Split the string into three fields.
  • 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 $price instead of the empty string.
  • Invoke the format statement by using the write() function.

The Perl code (report3.pl) is as follows:

format =

Album=@<<<<<<<<<<<<< Artist=@>>>>>>>>>>>> Price=$@##.##

$album, $artist, $price

.

open(FILE, "

@lines = ;

close(FILE);


foreach (@lines) {

chop;

($album, $artist, $price) = (split(/!/));

$album = "" if !defined($album);

$artist = "" if !defined($artist);

$price = 0 if !defined($price);

write();

}

This program displays the following:

  Album=A Love Supreme  Artist=                      Price=$  0.00
Album=A Kind of Blue Artist= Miles Davis Price=.99
Album=Koln Concert Artist= Keith Jarrett Price=$ 15.99
Album=Birds of Fire Artist= Mahvishnu Orchestra Price=$ 10.99

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.

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.

Report Headings

Format statements for a report heading use the same format as the detail line format statement, except that _TOP is appended to the file handle. In the case of STDOUT, you must specify STDOUT_TOP. Simply using _TOP will not work.

To add a heading to the report about the CD collection, you might use the following format statement (report4.pl):

format STDOUT_TOP =

@|||||||||||||||||||||||||||||||||||| Pg @<

"CD Collection of David Marshall",
$%


Album Artist Price

----------------- ---------------- -------

Adding this format statement to last code listing produces this output:
      CD Collection of David Marshall       Pg 1
Album Artist Price
----------------- ---------------- -------
A Love Supreme $ 0.00
A Kind of Blue Miles Davis $ 9.99
Koln Concert Keith Jarrett $ 15.99
Birds of Fire Mahvishnu Orchestra $ 10.99

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.

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.