cvs commit: perlfaq perlfaq6.pod

[email protected]
Newsgroups perl.cvs.perlfaq
Message-ID <[email protected]>
cvsuser     02/10/30 10:44:21

  Modified:    .        perlfaq6.pod
  Log:
  *this is almost a complete re-write of the answer.
     + the original usenet message example was a bit complicated
     + the code did not actually do what it said it did anyway
     + it was not clear what it should do
  
  my answer is more elementary.
     + call the \G anchor an "anchor" to build on reader's knowledge
     of other anchors (^, $)
     + mentions pos() so readers have another place to look for info
     + uses a small string in examples that are ready to run
     + adds a small example of the c flag before Jeffery's big example with it
     + adds an explantion of Jeffery's example
  
  Revision  Changes    Path
  1.18      +84 -57    perlfaq/perlfaq6.pod
  
  Index: perlfaq6.pod
  ===================================================================
  RCS file: /cvs/public/perlfaq/perlfaq6.pod,v
  retrieving revision 1.17
  retrieving revision 1.18
  diff -u -w -r1.17 -r1.18
  --- perlfaq6.pod	21 Sep 2002 21:04:17 -0000	1.17
  +++ perlfaq6.pod	30 Oct 2002 18:44:21 -0000	1.18
  @@ -1,6 +1,6 @@
   =head1 NAME
   
  -perlfaq6 - Regular Expressions ($Revision: 1.17 $, $Date: 2002/09/21 21:04:17 $)
  +perlfaq6 - Regular Expressions ($Revision: 1.18 $, $Date: 2002/10/30 18:44:21 $)
   
   =head1 DESCRIPTION
   
  @@ -563,69 +563,96 @@
   
   =head2 What good is C<\G> in a regular expression?
   
  -The notation C<\G> is used in a match or substitution in conjunction with
  -the C</g> modifier to anchor the regular expression to the point just past
  -where the last match occurred, i.e. the pos() point.  A failed match resets
  -the position of C<\G> unless the C</c> modifier is in effect. C<\G> can be
  -used in a match without the C</g> modifier; it acts the same (i.e. still
  -anchors at the pos() point) but of course only matches once and does not
  -update pos(), as non-C</g> expressions never do. C<\G> in an expression
  -applied to a target string that has never been matched against a C</g>
  -expression before or has had its pos() reset is functionally equivalent to
  -C<\A>, which matches at the beginning of the string.
  -
  -For example, suppose you had a line of text quoted in standard mail
  -and Usenet notation, (that is, with leading C<< > >> characters), and
  -you want change each leading C<< > >> into a corresponding C<:>.  You
  -could do so in this way:
  -
  -     s/^(>+)/':' x length($1)/gem;
  -
  -Or, using C<\G>, the much simpler (and faster):
  -
  -    s/\G>/:/g;
  -
  -A more sophisticated use might involve a tokenizer.  The following
  -lex-like example is courtesy of Jeffrey Friedl.  It did not work in
  -5.003 due to bugs in that release, but does work in 5.004 or better.
  -(Note the use of C</c>, which prevents a failed match with C</g> from
  -resetting the search position back to the beginning of the string.)
  +You use the C<\G> anchor to start the next match on the same
  +string where the last match left off.  The regular
  +expression engine cannot skip over any characters to find
  +the next match with this anchor, so C<\G> is similar to the
  +beginning of string anchor, C<^>.  The C<\G> anchor is typically
  +used with the C<g> flag.  It uses the value of pos()
  +as the position to start the next match.  As the match
  +operator makes successive matches, it updates pos() with the
  +position of the next character past the last match (or the
  +first character of the next match, depending on how you like
  +to look at it). Each string has its own pos() value.
  +
  +Suppose you want to match all of consective pairs of digits
  +in a string like "1122a44" and stop matching when you
  +encounter non-digits.  You want to match C<11> and C<22> but
  +the letter <a> shows up between C<22> and C<44> and you want
  +to stop at C<a>. Simply matching pairs of digits skips over
  +the C<a> and still matches C<44>.
  +
  +	$_ = "1122a44";
  +	my @pairs = m/(\d\d)/g;   # qw( 11 22 44 )
  +
  +If you use the \G anchor, you force the match after C<22> to
  +start with the C<a>.  The regular expression cannot match
  +there since it does not find a digit, so the next match
  +fails and the match operator returns the pairs it already
  +found.
   
  -    while (<>) {
  -      chomp;
  -      PARSER: {
  -           m/ \G( \d+\b    )/gcx    && do { print "number: $1\n";  redo; };
  -           m/ \G( \w+      )/gcx    && do { print "word:   $1\n";  redo; };
  -           m/ \G( \s+      )/gcx    && do { print "space:  $1\n";  redo; };
  -           m/ \G( [^\w\d]+ )/gcx    && do { print "other:  $1\n";  redo; };
  +	$_ = "1122a44";
  +	my @pairs = m/\G(\d\d)/g; # qw( 11 22 )
  +
  +You can also use the C<\G> anchor in scalar context. You
  +still need the C<g> flag.
  +
  +	$_ = "1122a44";
  +	while( m/\G(\d\d)/g )
  +		{
  +		print "Found $1\n";
         }
  +		
  +After the match fails at the letter C<a>, perl resets pos()
  +and the next match on the same string starts at the beginning.
  +
  +	$_ = "1122a44";
  +	while( m/\G(\d\d)/g )
  +		{
  +		print "Found $1\n";
       }
   
  -Of course, that could have been written as
  +	print "Found $1 after while" if m/(\d\d)/g; # finds "11"
  +
  +You can disable pos() resets on fail with the C<c> flag.
  +Subsequent matches start where the last successful match
  +ended (the value of pos()) even if a match on the same
  +string as failed in the meantime. In this case, the match
  +after the while() loop starts at the C<a> (where the last
  +match stopped), and since it does not use any anchor it can
  +skip over the C<a> to find "44".
  +
  +	$_ = "1122a44";
  +	while( m/\G(\d\d)/gc )
  +		{
  +		print "Found $1\n";
  +		}
  +
  +	print "Found $1 after while" if m/(\d\d)/g; # finds "44"
  +
  +Typically you use the C<\G> anchor with the C<c> flag
  +when you want to try a different match if one fails,
  +such as in a tokenizer. Jeffrey Friedl offers this example
  +which works in 5.004 or later.
   
       while (<>) {
         chomp;
         PARSER: {
  -	   if ( /\G( \d+\b    )/gcx  {
  -		print "number: $1\n";
  -		redo PARSER;
  -	   }
  -	   if ( /\G( \w+      )/gcx  {
  -		print "word: $1\n";
  -		redo PARSER;
  -	   }
  -	   if ( /\G( \s+      )/gcx  {
  -		print "space: $1\n";
  -		redo PARSER;
  -	   }
  -	   if ( /\G( [^\w\d]+ )/gcx  {
  -		print "other: $1\n";
  -		redo PARSER;
  -	   }
  +           m/ \G( \d+\b    )/gcx   && do { print "number: $1\n";  redo; };
  +           m/ \G( \w+      )/gcx   && do { print "word:   $1\n";  redo; };
  +           m/ \G( \s+      )/gcx   && do { print "space:  $1\n";  redo; };
  +           m/ \G( [^\w\d]+ )/gcx   && do { print "other:  $1\n";  redo; };
         }
       }
   
  -but then you lose the vertical alignment of the regular expressions.
  +For each line, the PARSER loop first tries to match a series
  +of digits followed by a word boundary.  This match has to
  +start at the place the last match left off (or the beginning
  +of the string on the first match). Since C<m/ \G( \d+\b   
  +)/gcx> uses the C<c> flag, if the string does not match that
  +regular expression, perl does not reset pos() and the next
  +match starts at the same position to try a different
  +pattern.
   
   =head2 Are Perl regexes DFAs or NFAs?  Are they POSIX compliant?
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.