Perl global matching
last modified October 20, 2026
The /g modifier makes a match global. What it does depends on the
context: in list context it returns all matches, and in scalar context it
iterates through them one at a time, tracking the position with
pos. Combined with the \G anchor and the
/c flag, it can be used to write small parsers.
Global matching in scalar context
In scalar context, a match with /g remembers where it stopped in
the string. The next match with /g on the same variable continues
from there, which is what makes while loops over matches work. The
position can be read with pos.
#!/usr/bin/perl
use strict;
use warnings;
use v5.34.0;
my $text = 'cat bat rat';
while ($text =~ /(\w)at/g) {
say "found '$&' ending at ", pos($text), ", first letter $1";
}
say "after the loop pos is: ", defined pos($text) ? pos($text) : 'undef';
$text =~ /bat/g;
say "single match leaves pos: ", pos($text);
$text =~ /cat/g or say "no cat after bat; pos reset: ", defined pos($text) ? pos($text) : 'undef';
Each pass of the loop finds the next word ending in at, and
pos reports the offset just after the match. When the match finally
fails, the position is reset to undef. A single match with /g
outside a loop leaves the position set, so a later /g match on the
same variable starts there; that is a common source of surprises, and a failed
match resets it again.
$ perl scalar.pl found 'cat' ending at 3, first letter c found 'bat' ending at 7, first letter b found 'rat' ending at 11, first letter r after the loop pos is: undef single match leaves pos: 7 no cat after bat; pos reset: undef
Global matching in list context
In list context, /g returns all the matches at once. Without
capture groups it returns the matched strings. With groups it returns the
captures of every match in one flat list.
#!/usr/bin/perl
use strict;
use warnings;
use v5.34.0;
my $text = 'a1 b22 c333';
my @numbers = $text =~ /\d+/g;
say "numbers: @numbers";
my @pairs = $text =~ /([a-z])(\d+)/g;
say "pairs flat: @pairs";
my %h = $text =~ /([a-z])(\d+)/g;
say "as hash: ", join ', ', map { "$_=$h{$_}" } sort keys %h;
my $count = () = $text =~ /\d/g;
say "digits: $count";
my @words = 'one, two;three four' =~ /\w+/g;
say "words: ", scalar @words;
The flat list of captures can be assigned to a hash, which turns key-value pairs
in text into a lookup table in one line. The () = ... idiom, with
the result assigned to a scalar, counts the matches, and \w+ with
/g in list context is a simple way to split text into words.
$ perl list.pl numbers: 1 22 333 pairs flat: a 1 b 22 c 333 as hash: a=1, b=22, c=333 digits: 6 words: 4
Tokenizing with \G and /gc
The assertion \G matches at the position where the last
/g match ended. The /c flag keeps that position when a
match fails. Together they let a loop try several patterns at the same spot,
which is how a lexer works.
#!/usr/bin/perl
use strict;
use warnings;
use v5.34.0;
my $src = 'total = 3 + 42 * rate';
my @tokens;
for ($src) {
while (1) {
if (/\G\s+/gc) { next }
elsif (/\G(\d+)/gc) { push @tokens, "NUM($1)" }
elsif (/\G([A-Za-z_]\w*)/gc) { push @tokens, "ID($1)" }
elsif (/\G([=+*\/-])/gc) { push @tokens, "OP($1)" }
elsif (/\G\z/gc) { last }
else { die "unexpected input\n" }
}
}
say join ' ', @tokens;
my $bad = 'x = 5 $ 2';
eval {
for ($bad) {
while (1) {
if (/\G\s+/gc) { next }
elsif (/\G\w+/gc) { next }
elsif (/\G=/gc) { next }
elsif (/\G\z/gc) { last }
else { die sprintf "unexpected '%s' at position %d\n", substr($_, pos), pos }
}
}
};
print "error: $@";
The loop tries each token type in turn at the current position: whitespace,
number, identifier, operator, and the end of the string. Because every pattern
starts with \G and uses /gc, a failure does not reset
the position and the next alternative starts in the same place. The for
($src) construct aliases the string to $_. If no pattern
matches, the loop dies. The second part shows an error message with the
offending text and its position.
$ perl lexer.pl ID(total) OP(=) NUM(3) OP(+) NUM(42) OP(*) ID(rate) error: unexpected '$ 2' at position 6
Working with pos
The pos function returns the current position and can also be
assigned to, so scanning can start or restart at any offset.
#!/usr/bin/perl use strict; use warnings; use v5.34.0; my $s = 'aaa bbb ccc'; $s =~ /\w+/g; say "after first word: ", pos($s); pos($s) = 8; $s =~ /\w+/g; say "matched from 8: $&"; pos($s) = 0; my @rest = $s =~ /\G(\w+)\s*/g; say "\\G chain: @rest"; $s =~ /bbb/g; say "pos after bbb: ", pos($s); $s =~ /zzz/gc; say "failed /gc keeps pos: ", pos($s); $s =~ /zzz/g; say "failed /g resets pos: ", defined pos($s) ? pos($s) : 'undef';
After the first word the position is 3. Assigning 8 jumps over the second word,
and the next match returns ccc. A chain of \G matches
in list context collects the words from position 0. A failed /gc
match leaves the position alone, while a failed /g match resets it
to undef.
$ perl pos.pl after first word: 3 matched from 8: ccc \G chain: aaa bbb ccc pos after bbb: 7 failed /gc keeps pos: 7 failed /g resets pos: undef
Empty matches
A pattern that can match the empty string, such as x*, matches at
every position. Perl prevents an endless loop by not allowing an empty match at
the same place twice.
#!/usr/bin/perl use strict; use warnings; use v5.34.0; my $s = 'abc'; my $n = () = $s =~ /x*/g; say "empty matches in 'abc': $n"; (my $spaced = $s) =~ s/x*/-/g; say $spaced; (my $between = $s) =~ s/(?<=.)(?=.)/-/g; say $between;
In a string of three characters there are four positions, so x*
produces four empty matches. Replacing them inserts a dash everywhere, including
both ends. The lookaround version inserts a dash only between characters.
$ perl empty.pl empty matches in 'abc': 4 -a-b-c- a-b-c
Best Practices
- Choose the context deliberately: list context collects, scalar context iterates.
- Do not reuse a variable with a stale pos: reset it with
pos($s) = undefif needed. - Use \G with /gc for tokenizers: failures keep the position.
- Beware of the empty match: patterns that can match nothing return extra matches.
- Copy before modifying: changing the string resets
pos.
In this article we have covered global matching: scalar and list context,
pos, \G with /gc, and empty matches.
Source
perlop: Regexp Quote-Like Operators
Author
List all Perl tutorials.