#!perl -w
use English;
$total_lines = $quoted_lines = 0;
while (<>)
{
++$total_lines;
++$quoted_lines if /^>/;
}
$percent = ($quoted_lines * 100)/$total_lines;
print "$quoted_lines lines were quoted out of a total of $total_lines: $percent%\n";
though you might want to screen out entirely blank lines, and you should be
worried about the spurious accuracy in output like this:
4 lines were quoted out of a total of 14: 28.5714285714286%See Chapter 6 for ways of controlling this sort of thing.
#!perl -w
while (<>)
{
s/_([a-z])/\u$1/g ;
print;
}
Slick, but it doesn't handle underlines at the very beginning or end, or
two of them in a row. Can you do better?
(Everyone I showed this question to told me how awful they thought the
mixed-case convention was, so maybe you ought to be doing the vice
versa option to this one anyway.)
Back to the question.
#!perl -w
use English;
$property_name = '[A-Z]\w*';
while (<>)
{
chomp;
if (/add($property_name)Listener/)
{
print $ARG, " : listener adder for $1 event\n";
}
elsif (/remove($property_name)Listener/)
{
print $ARG, " : listener remover for $1 event\n";
}
elsif (/get($property_name)/)
{
print $ARG, " : get method for $1 property\n";
}
elsif (/set($property_name)/)
{
print $ARG, " : set method for $1 property\n";
}
elsif (/is($property_name)/)
{
print $ARG, " : test method for Boolean property $1\n";
}
else
{
print $ARG, " : ordinary method or something\n";
}
}
Here, I am just assuming the data consists of one name per line, as it does
in my test data file. Try
changing the script so it extracts the names from a Java program.
$x = shift(@a) == $x = splice(@a, 0, 1) unshift(@a, $x) == splice(@a, 0, 0, $x)(Actually, unshift can take any number of trailing arguments, just apply the same transformation to them.)
sub num_to_base {
my ($n, $b) = @ARG;
if ($n < $b)
{
return sprintf("%X", $n);
}
else
{
return num_to_base($n/$b, $b) . sprintf("%X", $n%$b);
}
}
sub number_to_base {
my ($n, $b) = @ARG;
($b > 1 && $b <= 16) || die "number base must be between 2 and 16, not $b\n";
return $n < 0? '-' . num_to_base(-$n, $b): num_to_base($n, $b);
}
I first came across this algorithm as the writen function in the
BCPL standard library. (What do you mean, you never heard of BCPL?)
If you want to get rid of the restriction to bases less than 16, you have
to provide a replacement for the call to sprintf, probably using a
lookup table, but you also have to invent the extra digits.
Back to the question.
sub sort_strings {
return sort {
length($a) <=> length($b)
} @ARG;
}
or define a separate comparison subroutine if you prefer.
elsif (/get($property_name)/)
{
++$get_method{$1};
}
and so on. You might even want to use a sixth, to record every name you
encounter, so you can just iterate over its keys when you come to do the
classification.
$INPUT_RECORD_SEPARATOR = '';
$longest = '';
$longest_length = 0;
while (<>)
{
length($ARG) > $longest_length and
($longest, $longest_length) = ($ARG, length($ARG))
}
print $longest;
My script is less efficient than it might be, too.
opendir DIR, $folder or die "I can't open $folder\n";
chdir $folder or die "couldn't change directory to $folder";
@files = grep { /\.(\d+)$/ } (readdir DIR);
closedir DIR;
$highest = $#files;
$lowest = 0;
if (-e 'Reversed Temp File')
{
die "Reverse temporary file already exists";
}
while ($highest > $lowest)
{
rename $files[$highest], 'Reversed Temp File' or die "rename failed";
rename $files[$lowest], $files[$highest] or die "rename failed";
rename 'Reversed Temp File', $files[$lowest] or die "rename failed";
++$lowest;
--$highest;
}
The logic is essentially the same as you would use to reverse the
elements of an array, if you had to do it by hand, except that
instead of swapping elements we rename the files whose names they
hold. In both cases, what you need to take care not to do is
overwrite an element with the one you are swapping it with without
saving its value somewhere. Here, I use a temporary file name
where you would use a temporary variable while performing the
exchange.