Perl Help?

Alert to regular readers of this blog: If you don’t care about Perl (or are not sure whether you care about Perl!), stop right here, or risk death by confusion or boredom!

I have a nasty problem at work that I just can’t get through. One of the many applications of Perl that I’ve written at work is a verification and reporting suite that starts with text outputs of software that does computations, and is required to create HTML reports that reproduce the output files, but with the numbers color-coded based on how they verified against the benchmark numbers. But these output files have a lot of numbers, and sometimes the exact same numbers (to 4 decimal places) show up multiple times, and it gets quite tricky to color-code just the right ones every time.

So I recently thought I arrived at an beautiful solution with an elegant global-substitution Regular Expression, but it didn’t quite work. Consider the following small Perl program, in which “<span color=”green”>1<span>” is abbreviated as “sg1s

#! /bin/perl
$s = "1 2 3 1 2 3 1 2 3";          # what I have
$t = "sg1s 2 3 sr1s 2 3 1 sy2s 3"; # what I want
@nums = qw(1 1 2);
@cols = qw(g r y);
$i=$j=0;
$s =~ s!($nums[$i++])!s$cols[$j++]$1s!g;
print "Want: '$t'\n";
print "Got:  '$s'\n";
print "i is now $i\n";
print "j is now $j\n";

The output of this program is unfortunately:

Want: 'sg1s 2 3 sr1s 2 3 1 sy2s 3'
Got:  'sg1s 2 3 sr1s 2 3 sy1s 2 3'
i is now 1
j is now 3

Perl ended up incorrectly coloring the third ‘1’ yellow, instead of the third ‘2’, because in the substitution regular expression, the left (matching) side was evaluated/compiled only once, while the right (replacement) side was evaluated/interpolated three times (as desired).

I know that there are ways to force the left side of the RE to compile only once (/o modifier, qr// operator), and there are ways to force eval in the right side (/e and /ee modifiers — although in this case, standard interpolation was sufficient), but is there any way I can force the left side to compile multiple times? (Even within the same /g substitution?) I tried a few constructs using the \G (start matching from previous position) zero-width assertion, but only managed to get myself into infinite loops.

Any ideas, please drop a comment, or send me a gmail (same user name as here at WordPress.com).

Advertisements

One Response

  1. Problem solved, thanks to San Diego Perl-Mongers!. For a script with a more illustrative example, and a bunch of options (bad and good), see here

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: