ZetCode

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.

scalar.pl
#!/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.

list.pl
#!/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.

lexer.pl
#!/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.

pos.pl
#!/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.

empty.pl
#!/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

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

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Perl tutorials.