What good is \G in a regular expression?

\G in a regular expression?

The notation \G is used in a match or substitution in conjunction with the /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 \G unless the /c modifier is in effect. \G can be used in a match without the /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-/g expressions never do. \G in an expression applied to a target string that has never been matched against a /g expression before or has had its pos() reset is functionally equivalent to \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 > characters), and you want change each leading > into a corresponding :. You could do so in this way:

     s/^(>+)/':' x length($1)/gem;
Or, using \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, which prevents a failed match with /g from resetting the search position back to the beginning of the string.)

    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; };
      }
    }
Of course, that could have been written as

    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;
	   }
      }
    }
but then you lose the vertical alignment of the regular expressions.
Back to perlfaq6