Recipe 2.17 Printing Correct Plurals
2.17.1 Problem
You're printing something like
"It took
$time hours", but
"It took 1
hours" is ungrammatical. You would like to get it
right.
2.17.2 Solution
Use printf and the conditional operator
(X ? Y
: Z) to alter the noun or verb:
printf "It took %d hour%s\n", $time, $time = = 1 ? "" : "s";
printf "%d hour%s %s enough.\n", $time,
$time = = 1 ? "" : "s",
$time = = 1 ? "is" : "are";
Or use the Lingua::EN::Inflect module
from CPAN, as described in the following Discussion.
2.17.3 Discussion
The only reason inane messages like "1
file(s) updated" appear is
because their authors are too lazy to bother checking whether the
count is 1 or not.
If your noun changes by more than an "-s", you'll
need to change the printf accordingly:
printf "It took %d centur%s", $time, $time = = 1 ? "y" : "ies";
This is good for simple cases, but you'll tire of writing it. This
leads you to write funny functions like this:
sub noun_plural {
local $_ = shift;
# order really matters here!
s/ss$/sses/ ||
s/([psc]h)$/${1}es/ ||
s/z$/zes/ ||
s/ff$/ffs/ ||
s/f$/ves/ ||
s/ey$/eys/ ||
s/y$/ies/ ||
s/ix$/ices/ ||
s/([sx])$/$1es/ ||
s/$/s/ ||
die "can't get here";
return $_;
}
*verb_singular = \&noun_plural; # make function alias
As you find more exceptions, your function will become increasingly
convoluted. When you need to handle such morphological changes, turn
to the flexible solution provided by the Lingua::EN::Inflect module
from CPAN.
use Lingua::EN::Inflect qw(PL classical);
classical(1); # why isn't this the default?
while (<DATA>) { # each line in the data
for (split) { # each word on the line
print "One $_, two ", PL($_), ".\n";
}
}
# plus one more
$_ = 'secretary general';
print "One $_, two ", PL($_), ".\n";
_ _END_ _
fish fly ox
species genus phylum
cherub radius jockey
index matrix mythos
phenomenon formula
That produces the following:
One fish, two fish.
One fly, two flies.
One ox, two oxen.
One species, two species.
One genus, two genera.
One phylum, two phyla.
One cherub, two cherubim.
One radius, two radii.
One jockey, two jockeys.
One index, two indices.
One matrix, two matrices.
One mythos, two mythoi.
One phenomenon, two phenomena.
One formula, two formulae.
One secretary general, two secretaries general.
Without calling classical, these lines would have
come out different than in the previous output:
One phylum, two phylums.
One cherub, two cherubs.
One radius, two radiuses.
One index, two indexes.
One matrix, two matrixes.
One formula, two formulas.
This is just one of the many things the module can do. It also
handles inflections or conjugations for other parts of speech,
provides number-insensitive comparison functions, figures out whether
to use a or an, and
plenty more.
2.17.4 See Also
The "Conditional Operator" in perlop(1) and
Chapter 3 of Programming Perl; the
documentation with the CPAN module Lingua::EN::Inflect
|