A.5. Answers to Chapter 6 Exercises
-
Here's one way to do it:
print reverse <>;
Well, that's pretty simple! But it works because
print is looking for a list of strings to print,
which it gets by calling reverse in a list
context. And reverse is looking for a list of
strings to reverse, which it gets by using the diamond operator in
list context. So, the diamond returns a list of all of the lines from
all of the files of the user's choice. That list of lines is
just what cat would print out. Now
reverse reverses the list of lines, and
print prints them out.
-
Here's one way to do it:
print "Enter some lines, then press Ctrl-D:\n"; # or Ctrl-Z
chomp(my @lines = <STDIN>);
print "1234567890" x 7, "12345\n"; # ruler line to column 75
foreach (@lines) {
printf "%20s\n", $_;
}
Here, we start by reading in and chomping all of the lines of text.
Then we print the ruler line. Since that's a debugging aid,
we'd generally comment-out that line when the program is done.
We could have typed "1234567890" again and again,
or even used copy-and-paste to make a ruler line as long as we
needed, but we chose to do it this way because it's kind of
cool.
Now, the foreach loop iterates over the list of
lines, printing each one with the %20s conversion.
If you chose to do so, you could have created a format to print the
list all at once, without the loop:
my $format = "%20s\n" x @lines;
printf $format, @lines;
It's a common mistake to get 19-character columns. That happens
when you say to yourself,[385] "Hey, why do we
chomp the input if we're only going to add
the newlines back on later?" So you leave out the
chomp and use a format of
"%20s" (without a newline).[386] And now,
mysteriously, the output is off by one space. So, what went wrong?
The problem happens when Perl tries to count the spaces needed to
make the right number of columns. If the user enters
hello and a newline, Perl sees
six characters, not five, since newline is a
character. So it prints fourteen spaces and a six-character string,
sure that it gives the twenty characters you asked for in
"%20s". Oops.
Of course, Perl isn't looking at the contents of the string to
determine the width; it merely checks the raw number of characters. A
newline (or another special character, such as a tab or a null
character) will throw things off.[387]
-
Here's one way to do it:
print "What column width would you like? ";
chomp(my $width = <STDIN>);
print "Enter some lines, then press Ctrl-D:\n"; # or Ctrl-Z
chomp(my @lines = <STDIN>);
print "1234567890" x (($width+9)/10), "\n"; # ruler line as needed
foreach (@lines) {
printf "%${width}s\n", $_;
}
This is much like the previous one, but we ask for a column width
first. We ask for that first because we can't ask for more
input after the end-of-file indicator, at least
on some systems. Of course, in the real world, you'll generally
have a better end-of-input indicator when getting input from the
user, as we'll see in later chapters.
Another change from the previous exercise's answer is the ruler
line. We used some math to cook up a ruler line that's at least
as long as we need, as suggested as an "extra credit"
part of the exercise. Proving that our math is correct is an
additional challenge. (Hint: Consider possible widths of
50 and 51, and remember that
the right side operand to x is truncated, not
rounded.)
To generate the format this time, we used the expression
"%${width}s\n", which interpolates
$width. The curly braces are required to
"insulate" the name from the following
s; without the curly braces, we'd be
interpolating $widths, the wrong variable. If you
forgot how to use curly braces to do this, though, you could have
written an expression like '%' . $width . "s\n" to
get the same format string.
The value of $width brings up another case where
chomp is vital. If the width isn't
chomped, the resulting format string would resemble
"%30\ns\n". That's not useful.
People who have seen printf before may have
thought of another solution. Because printf
comes to us from C, which doesn't have string interpolation, we
can use the same trick that C programmers use. If an asterisk
("*") appears in place of a numeric
field width in a conversion, a value from the list of parameters will
be used:
printf "%*s\n", $width, $_;
| | | A.4. Answers to Chapter 5 Exercises | | A.6. Answers to Chapter 7 Exercises |
Copyright © 2002 O'Reilly & Associates. All rights reserved.
|
|