cvs commit: perlfaq perlfaq6.pod

[email protected] 31 Jan 2005 15:45:36 -0000
Newsgroups perl.cvs.perlfaq
Message-ID <[email protected]>
cvsuser     05/01/31 07:45:36

  Modified:    .        perlfaq6.pod
  Log:
  * updated the answer so that we don't think perl5.005 is the
  newest version of perl
  
  * cleaned up the examples to give them parallel structure and
  to generalize the method.  (What was popstates anyway?)
  
  * added another example
  
  * mention Mastering Regular Expressions to motivate people to
  find out how regexes work and that they can be tuned.
  
  Revision  Changes    Path
  1.29      +51 -25    perlfaq/perlfaq6.pod
  
  Index: perlfaq6.pod
  ===================================================================
  RCS file: /cvs/public/perlfaq/perlfaq6.pod,v
  retrieving revision 1.28
  retrieving revision 1.29
  diff -u -r1.28 -r1.29
  --- perlfaq6.pod	3 Jan 2005 18:43:37 -0000	1.28
  +++ perlfaq6.pod	31 Jan 2005 15:45:36 -0000	1.29
  @@ -1,6 +1,6 @@
   =head1 NAME
   
  -perlfaq6 - Regular Expressions ($Revision: 1.28 $, $Date: 2005/01/03 18:43:37 $)
  +perlfaq6 - Regular Expressions ($Revision: 1.29 $, $Date: 2005/01/31 15:45:36 $)
   
   =head1 DESCRIPTION
   
  @@ -518,32 +518,58 @@
   
   =head2 How do I efficiently match many regular expressions at once?
   
  -The following is extremely inefficient:
  +( contributed by brian d foy )
   
  -    # slow but obvious way
  -    @popstates = qw(CO ON MI WI MN);
  -    while (defined($line = <>)) {
  -	for $state (@popstates) {
  -	    if ($line =~ /\b$state\b/i) {
  -		print $line;
  -		last;
  -	    }
  -	}
  -    }
  +Avoid asking Perl to compile a regular expression every time 
  +you want to match it.  In this example, perl must recompile
  +the regular expression for every iteration of the foreach()
  +loop since it has no way to know what $pattern will be.
  +
  +    @patterns = qw( foo bar baz );
  +    
  +    LINE: while( <> ) 
  +    	{
  +		foreach $pattern ( @patterns ) 
  +			{
  +	    	print if /\b$pattern\b/i;
  +	    	next LINE;
  +	   		}
  +		}
   
  -That's because Perl has to recompile all those patterns for each of
  -the lines of the file.  As of the 5.005 release, there's a much better
  -approach, one which makes use of the new C<qr//> operator:
  -
  -    # use spiffy new qr// operator, with /i flag even
  -    use 5.005;
  -    @popstates = qw(CO ON MI WI MN);
  -    @poppats   = map { qr/\b$_\b/i } @popstates;
  -    while (defined($line = <>)) {
  -	for $patobj (@poppats) {
  -	    print $line if $line =~ /$patobj/;
  -	}
  -    }
  +The qr// operator showed up in perl 5.005.  It compiles a
  +regular expression, but doesn't apply it.  When you use the
  +pre-compiled version of the regex, perl does less work. In
  +this example, I inserted a map() to turn each pattern into
  +its pre-compiled form.  The rest of the script is the same,
  +but faster.
  +
  +    @patterns = map { qr/\b$_\b/i } qw( foo bar baz );
  +
  +    LINE: while( <> ) 
  +    	{
  +		foreach $pattern ( @patterns ) 
  +			{
  +	    	print if /\b$pattern\b/i;
  +	    	next LINE;
  +	   		}
  +		}
  +		
  +In some cases, you may be able to make several patterns into
  +a single regular expression.  Beware of situations that require
  +backtracking though.
  +
  +	$regex = join '|', qw( foo bar baz );
  +
  +    LINE: while( <> ) 
  +    	{
  +		print if /\b(?:$regex)\b/i;
  +		}
  +
  +For more details on regular expression efficiency, see Mastering
  +Regular Expressions by Jeffrey Freidl.  He explains how regular
  +expressions engine work and why some patterns are surprisingly
  +inefficient.  Once you understand how perl applies regular 
  +expressions, you can tune them for individual situations.
   
   =head2 Why don't word-boundary searches with C<\b> work for me?