File Coverage

blib/lib/Regexp/Subst/Parallel.pm
Criterion Covered Total %
statement 36 37 97.3
branch 8 10 80.0
condition n/a
subroutine 7 7 100.0
pod 0 1 0.0
total 51 55 92.7


line stmt bran cond sub pod time code
1             package Regexp::Subst::Parallel;
2              
3 1     1   20118 use Exporter;
  1         2  
  1         41  
4 1     1   5 use Carp;
  1         1  
  1         597  
5              
6             our @ISA = qw/Exporter/;
7             our @EXPORT = qw/subst/;
8              
9             our $VERSION = 0.11;
10              
11             sub subst
12             {
13 27     27 0 55 my $str = shift;
14 27         36 my $pos = 0;
15 27         30 my @subs;
16 27         58 while (@_) {
17 76         218 push @subs, [ shift, shift ];
18             }
19 27         31 my $res;
20            
21 27         63 while ($pos < length $str) {
22 83         88 my (@bplus, @bminus, $best);
23 83         103 for my $rref (@subs) {
24 280         506 pos $str = $pos;
25 280 100       3349 if ($str =~ /\G$rref->[0]/) {
26 28 50       95 if ($+[0] > $bplus[0]) {
27 28         92 @bplus = @+;
28 28         88 @bminus = @-;
29 28         95 $best = $rref;
30             }
31             }
32             }
33 83 100       175 if (@bminus) {
34 28         41 my $temp = $best->[1];
35 28 100       70 if (ref $temp eq 'CODE') {
    50          
36 13         29 $res .= $temp->(map { substr $str, $bminus[$_], $bplus[$_]-$bminus[$_] } 0..$#bminus);
  20         90  
37             }
38             elsif (not ref $temp) {
39             # I can't help using it even before I'm done writing it!
40             $temp = subst($temp,
41 3     3   7 qr/\\\\/ => sub { '\\' },
42 3     3   8 qr/\\\$/ => sub { '$' },
43 4     4   14 qr/\$(\d+)/ => sub { substr $str, $bminus[$_[1]], $bplus[$_[1]]-$bminus[$_[1]] },
44 3     3   10 qr/\$\{(\d+)\}/ => sub { substr $str, $bminus[$_[1]], $bplus[$_[1]]-$bminus[$_[1]] },
45 15         262 );
46 15         119 $res .= $temp;
47             }
48             else {
49 0         0 croak 'Replacements must be strings or coderefs, not ' .
50             ref($temp) . ' refs';
51             }
52 28         105 $pos = $bplus[0];
53             }
54             else {
55 55         92 $res .= substr $str, $pos, 1;
56 55         162 $pos++;
57             }
58             }
59 27         133 return $res;
60             }
61              
62             =head1 NAME
63              
64             Regexp::Subst::Parallel - Safely perform multiple substitutions on a string
65             in parallel.
66            
67             =head1 VERSION
68              
69             Regexp::Subst::Parallel version 0.11, Feb 9, 2003.
70              
71             =head1 SYNOPSIS
72              
73             # Rephrase $str into the form of a question.
74             my $qstr = subst($str,
75             qr/I|me/ => 'you',
76             qr/my/ => 'your',
77             qr/mine/ => 'yours',
78             qr/you/ => 'me',
79             qr/your/ => 'my',
80             qr/yours/ => 'mine',
81             ...);
82            
83             # Apply implicit html highlighting
84             my $html = subst($text,
85             qr/\{(.*?)\}/ => '$1', # Protect things in braces
86             qr/_(\w+)_/ => '$1',
87             qr/<(\w+)>/ => '$1',
88             );
89              
90             # Toggle the case of every character
91             my $vAR = subst($Var,
92             qr/([a-z]+)/ => sub { uc $_[1] },
93             qr/([A-Z]+)/ => sub { lc $_[1] },
94             );
95              
96             =head1 DESCRIPTION
97              
98             C is a module that allows you to make
99             multiple simultaneous substitutions safely. Using the sole exported
100             C function has a rather different effect from doing each
101             substitution sequentially. For example:
102              
103             $text = '{process_the_data} was _called_ without !';
104             $text =~ s/\{(.*?)\}/$1/g;
105             # $text eq 'process_the_data was _called_ without !'
106             $text =~ s/_(\w+)_/$1/g;
107             # $text eq 'processthedata was called without !'
108             $text =~ s/<(\w+)>/$1/g;
109             # $text eq 'processuthedata was ucalled without data!'
110              
111             Which is clearly the wrong result. On the other hand,
112             C does them all in parallel, so:
113              
114             $text = '{process_the_data} was _called_ without !';
115             $text = subst($text,
116             qr/\{(.*?)\}/ => '$1', # Protect things in braces
117             qr/_(\w+)_/ => '$1',
118             qr/<(\w+)>/ => '$1',
119             );
120             # $text eq 'process_the_data was called without data'
121              
122             Which seems to be right.
123              
124             The algorithm moves from left to right, and the longest match is
125             substituted in case of conflict. The substitution side of the pairs
126             can either be a string, in which non-backslashed $n's are substituted,
127             or a coderef, in which the sub is called and passed the list of
128             captures in @_. $_[0] is analogous to $& : it refers to the entire
129             match.
130              
131             =head2 Gotchas
132              
133             Make sure when you're using the string method to have the $'s included
134             in the string. That means if you're using an interpolating quote ("",
135             qq{}, etc.) that you backslash $1, $2, etc. Otherwise you will get
136             the $n's from the current lexical scope, which is not what you want.
137              
138             =head2 Caveats
139              
140             To include a single backslash followed by an interpolated capture,
141             C needs to see '\\$1', which means that you have to type
142             '\\\\$1' when you just want I. That's sick.
143              
144             =head1 AUTHORS
145              
146             Luke Palmer
147              
148             =head1 COPYRIGHT
149              
150             Copyright (C) 2003 Luke Palmer. This module is distributed under the
151             same terms as Perl itself.
152              
153             http://www.perl.com/perl/misc/Artistic.html