/g in list and scalar context¶
Level: 201 · you loop over matches, count them, or reuse a /g match in an if
One line: In list context $s =~ /re/g returns every match at once; in scalar context it returns true or false for the next match and moves pos($s) past it — so while walks the string, my $n = $s =~ /re/g is 1 and not a count, an if (/re/g) searches from where the last one stopped, and a match written inside a function's argument list is in list context.
Perl decides what an expression returns from where it is used. For most operators that is a detail. For m//g it is two different operators with one spelling.
Measured¶
Verified output of match_g_pl.pl — regenerated by tools/run_examples.py, never hand-typed.
--- list context: every match at once ---
one group: 200 302 404
two groups: GET /home POST /login GET /missing
no groups: /home /login /missing
$n = () = ...: 2
--- scalar context: one match per call ---
$n = ...: 1 (true, not a count -- and pos($log) is now 3)
while: GET /home, pos($log) is now 9
while: POST /login, pos($log) is now 26
while: GET /missing, pos($log) is now 44
after the loop: pos($log) is undef, reset by the match that failed
--- if (/.../g) starts where the last match stopped ---
found POST, and pos($log) is now 19
searched from pos 19: no /home, and pos($log) is reset to undef
asked again, from the start: found /home
--- list context starts from pos() too ---
pos($log) is 9, left there by the last if
$log =~ /GET \S+/g returns: GET /missing
after pos($log) = undef: GET /home GET /missing
--- a match in an argument list is in list context ---
count_args($log =~ /GET/g) arguments: 2
count_args($log =~ /GET/) arguments: 1
count_args($log =~ /PUT/) arguments: 0
--- while without /g never moves ---
stopped by a guard after 1000 turns
List context: all at once¶
Assigned to an array, a /g match returns the groups of every match in order — one group gives the statuses, two groups give method and path flattened into one list, and no groups give the whole matches. my $n = () = $s =~ /re/g counts matches: the empty list () puts the match in list context, and a list assignment in scalar context is the number of elements on its right.
Scalar context: one per call, and pos()¶
In scalar context — my $n = ..., a while condition, an if — the match finds the next occurrence, returns true, and stores where it ended in pos($log). That is what makes while ($log =~ /.../g) walk the string one request at a time. When a match fails, pos is reset to undef, so the next search starts from the beginning.
pos belongs to the variable, not to the value. A copy has a position of its own — which is how this page's first draft printed undef for every position: it passed $log to a helper, and the helper's copy had never been searched.
The if that starts in the wrong place¶
The first if finds POST and leaves pos at 19. The second if asks about /home — which is in the string, at the start — and fails, because it searched from 19. That failure resets pos, so the same question asked a third time succeeds. Two identical if statements, two different answers.
List context reads pos too: with pos left at 9 by the last if, $log =~ /GET \S+/g skips the first GET /home.
A match in an argument list¶
Function arguments are a list, so f($s =~ /re/) calls the match in list context. A successful match with no groups passes one argument (1); a failed one passes none — not 0, not ''. A helper with a one-argument signature dies on it. With /g it passes one argument per match.
While without /g¶
Without /g there is no position to move, so while ($log =~ /GET/) matches the first GET forever. The program stops it with a guard.
What to do instead¶
my @all = $s =~ /re/g; # every match
my $n = () = $s =~ /re/g; # how many
while ($s =~ /re/g) { ... pos($s) } # walk, with positions
if ($s =~ /re/) { ... } # a yes/no question: no /g
f(scalar($s =~ /re/)); # a yes/no passed to a function
If you are coming from another language¶
- Python. The three uses are three functions —
re.findallfor all matches,re.finditerto walk,re.searchfor yes or no — and none keeps a hidden position between calls. - Java.
Matcher.find()is scalar-context/g: the position lives in theMatcherobject, so reusing one matcher for two questions has this page'sifproblem.
See also¶
s///andtr///return counts — the other operators whose result is not what it looks like- perlop, "Regexp Quote-Like Operators" ↗ and pos ↗