[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

Re: [FWP] Perl Filter Demos?



Rich Morin <rdm@cfcl.com> wrote:
>BBEdit (a fine GUI-based text editor for Macs) is capable of running
>MacPerl-based filters on selected text.  I understand that some other
>editors (e.g., vim) also have this capability.

>I would love to have some intriguing demo filters on hand at WWDC (the
>Apple World Wide Developers Conference) in a week or so.  They should
>have a strong "Gee Whiz!" factor.  It would also be nice if they can
>be explained to mortal programmers...

>Does anyone feel like suggesting (or even coding up :-) something?

A couple of quickies:

s/(\S+)/reverse $1/ge;

A few weeks ago, to my great surprise, I found myself on the Microsoft
campus interviewing for a job.  The job wasn't with Microsoft (or I
wouldn't have been there), but with a new company to be composed largely of
ex-Microsoft employees.  The interviewer asked me to come up with some code
that would reverse the order of all words in a file.  I blinked, and asked
if any language was permitted.  He said yes.  I quickly scratched out a
Perl solution similar to the above.  (Unfazed, he demanded I reimplement the
solution in Java.)

Speaking of which, back when I used to program in Java a lot, I would
often be faced with the job of assigning unique numbers to a large number
of static class constants that served the purpose of enums in C, eg:

public final static int RED = 0, ORANGE = 1, YELLOW = 2, GREEN = 3,
	/* ... several more lines ... */
	MAUVE = 103;

I quickly realized that Perl could make this task much easier.  I only had
to write the names, and let Perl fill in the numbers.  I would write
something like this:

public final static int RED, ORANGE, YELLOW, GREEN /* ... */;

...and then pipe it through this:

perl -pe 's/([A-Z]\w*)/"$1 = ".$n++/ge'

Sometimes I want to modify a big chunk of a file (or even the entire file),
but the transformation is nontrivial enough that typing it into my editor's
single command line makes it likely that errors will be introduced; or, I
might want to undo the transformation, modify it slightly, and reapply it.
There's a great trick that makes this kind of thing easy:  Just move the
cursor to just above the region to be transformed, and insert this text:

while (<DATA>) {
	#  apply transformations and print output
}
__DATA__

...then pipe the above, followed by the region to be transformed, through
perl.  Often it's desirable to operate on the entire region as one long
string; to do this, just use the variation:

undef $/;
$_ = <DATA>;
#  whatever
print;
__DATA__

As an example, just yesterday I was editing a C source file in which I had
defined several arrays of a structure, something like so:

my_struct foo[] = {
	{ "FieldOne", Field::STRING, 10 },
	{ "FieldTwo", Field::CONSTANT, 0, "some string" },
	{ "FieldThree", Field::INTEGER, 20 },
};

I was retooling the data structures that were initialized by these arrays,
and I wanted to do the following:

1)  Replace Field::STRING and Field::INTEGER with the strings "S" and "I",
respectively.

2)  Replace Field::CONSTANT with the string "C" appended with the string
given as the fourth element of the struct.

3)  The name and width for constant fields were superfluous, so replace the
name with 0 and eliminate the width.

There were hundreds of lines to alter, but I converted the entire file by
piping it through a filter like this:

while (<DATA>) {
	if (/^ *{ (.*) },$/) {
		@array = split /, */, $1;
		if ($array[1] eq 'Field::STRING') {
			$array[1] = '"S"';
		} elsif ($array[1] eq 'Field::INTEGER') {
			$array[1] = '"I"';
		} elsif ($array[1] eq 'Field::CONSTANT' && $array[3] =~ /"(.*)"/) {
			@array = (0, qq("C$1"));
		}
		print "  { ", join(", ", @array), " },\n";
	} else {
		print;
	}
}
__DATA__

As expected, I made some mistakes before I was completely satisfied,
but all I had to do to recover from them was undo the transformation,
twiddle the Perl code, and re-pipe the file.

Finally (sheesh, I never thought this article would get so long!),
sometimes I write a block of code consisting solely of assignments, and I
decide the code would look better if all of the '=' characters were lined
up neatly.  I wrote a Perl program to do this, which I am currently unable
to locate.  It's pretty trivial to recreate, though:

----------------------------------------------------------------------
#!/usr/local/bin/perl

use strict;

my $char = @ARGV ? $ARGV[0] : '=';
my $max  = 0;
my ($index, @list);

while (<>) {
	push @list, $_;
	$index = index($_, $char);
	$max = $index if $index > $max;
}

foreach (@list) {
	s/(.*?)\Q$char/$1 . " " x ($max - length($1)) . $char/eo;
	print;
}
----------------------------------------------------------------------

Anyway, I hope some of these ideas are useful.

-- 
Sean McAfee | GCS d->-- s+++: a27 C++ US+++ P+++$ L++ E- W+ N++ |
            | K w--- O? M- V-- PS+ PE Y+ PGP?>++ t+() 5++ X R+  | mcafee@
            | tv+ b++ DI++ D+ G e++ h r---* y+>++               | umich.edu

==== Want to unsubscribe from Fun With Perl?  Well, if you insist...
==== Send email to <fwp-request@technofile.org> with message _body_
====   unsubscribe