Advanced Perl


OVERVIEW

These lectures examine the application of Perl to tasks commonly encountered by programmers.

As an interpreted language, Perl has features not normally found in compiled languages. We will focus on two of these features:

  1. Execution of expressions on the fly
  2. Associative arrays

EXPRESSIONS IN THE SUBSTITUTION FUNCTION

With the substitute function, we have seen extensive use of patterns in the first position. For example, s/[0-9]+/X/ will replace the leftmost integer with "X". However, complex expressions may appear in the second position as well, with the e option of the substitute function.

For example, the following code

	s/([0-9]+)/"X" x length($1)/e
will replace "abc123def" with "abcXXXdef".

Suppose that you have a lot of code that is indented on multiples of eight columns with tabs ("\t"), and you would prefer indentation on multiples of four columns. The retab program provides this service:

	# Usage: retab < infile > outfile

	$indent = 4;

	while (<STDIN>) {
		s#^(\t+)#' ' x (length($1) * 8)#e;
		s#^( *)#' ' x (length($1) * $indent / 8)#e;
		s#^(( {8})*)#"\t" x (length($1) / 8)#e;
		print;
	}

THE EVAL FUNCTION

The e option of the substitute function allows evaluation on the fly in string substitution. The eval function provides a more general form of expression evaluation. Any string can be evaluated as a Perl program. The string can be read from a file or generated on the fly.

Consider the following "hello world" program:

	$program = 'print "Hello world\n";';
	eval $program;
The rename program uses eval to solve a common programmer's problem. Suppose that you have a large number of files that you wish to rename in a uniform way. For example, you wish to change the .c suffix to .cpp. The rename program can do this and many other renaming tasks, in just a few lines of Perl:
	# Usage: rename perlExpression [files]

	# extract perlExpression from @ARGV[0]
	($op = shift) || die "Usage: rename perlExpression [files]\n";

	for (@ARGV) {
		$oldName = $_;
		eval $op;
		die $@ if $@;
		rename($oldName,$_) unless $oldName eq $_;
	}

ASSOCIATIVE ARRAYS

Example 1

Suppose that the following Perl program:
#!/public/bin/perl

while() {
	chop;
	foreach (split(/ /)) {
		if (defined($aa{$_})) {
			$aa{$_}++;
		} else {
			$aa{$_} = 1;
		}
	}
}

foreach (sort(keys(%aa))) {
	print "$_: $aa{$_}\n";
}
is run with the following input:
	Tree Ladle Picks (from "The Anguish Languish")

Once pawn term dare lift tree ladle picks.
Divorced ladle pick enter sickened ladle pick
wore lacy, fawn-laughing gauze.
Butter thread ladle pick ...

Example 2

Suppose that the Perl program from example 1 is modified as follows and run on the same input:
#!/public/bin/perl

while() {
	chop;
	foreach (split(/\W+/)) {
		tr/A-Z/a-z/;
		if (defined($aa{$_})) {
			$aa{$_}++;
		} else {
			$aa{$_} = 1;
		}
	}
}

foreach (sort(keys(%aa))) {
	print "$_: $aa{$_}\n";
}