Perl Part I · Module 11 · Regular Expressions
m// : Your First Match
This is the operator you will write more often than any other in Perl, and it is almost too easy to start using — put some text between slashes, and the match tells you whether your string contains it. The difficulty is not in writing one. It is that the match operator hands back four different things depending on the context it was called in and whether the pattern has capture groups, and three of those four look like success. The single most common bug written by engineers new to Perl is assigning a match to a plain scalar and getting the number 1 where they expected the matched text. Section four measures all four shapes side by side, and section five reduces the bug to the one character that causes it. The chapter closes on the default that makes Perl's one-liners possible and its scripts occasionally baffling: a pattern with nothing bound to it tests $_.
Foundation15 min readPerlPart IRegular Expressions
Part I · Module 11 · Chapter 11.2 · m// : Your First Match
1. The Simplest Possible Match
Put the text you are looking for between two slashes, bind it to a string with =~, and use it as a condition.
use strict;
use warnings;
my @lines = (
"ERROR: setup violation at u_alu/A",
"Info: 120 paths analysed",
"WARNING: clock gating disabled",
"no_error_found",
);
for my $line (@lines) {
if ($line =~ /ERROR/) {
print "hit : $line\n";
}
else {
print "pass: $line\n";
}
}hit : ERROR: setup violation at u_alu/A
pass: Info: 120 paths analysed
pass: WARNING: clock gating disabled
pass: no_error_foundOne of the four lines matched. There is no object to build, no pattern to compile, no result to unpack — the match is an expression that is true or false, so it drops straight into an if.
Look at the last line before moving on. no_error_found was not a hit, and it is worth being clear about why: the pattern is ERROR in capitals and the line says error in lowercase. Matching is case-sensitive by default. It was not rejected for being part of a longer word — a pattern will happily match inside a word, as the next section shows. That distinction trips people up constantly, and Chapter 11.8 is where we fix it properly.
2. "Contains", Not "Equals"
A pattern with no anchors asks whether the text contains the thing anywhere inside it.
use strict;
use warnings;
# A pattern asks "does this text CONTAIN this?" -- not "does it EQUAL this?"
my @subjects = ("ERROR", "ERROR: bad", "pre-ERROR", "x ERROR y", "erro", "Error");
for my $s (@subjects) {
printf "%-12s contains /ERROR/ : %s\n", "[$s]", ($s =~ /ERROR/ ? "yes" : "no");
}
print "\n";
printf "equality test \"ERROR\" eq \"ERROR: bad\" : %s\n",
("ERROR" eq "ERROR: bad" ? "true" : "false");[ERROR] contains /ERROR/ : yes
[ERROR: bad] contains /ERROR/ : yes
[pre-ERROR] contains /ERROR/ : yes
[x ERROR y] contains /ERROR/ : yes
[erro] contains /ERROR/ : no
[Error] contains /ERROR/ : no
equality test "ERROR" eq "ERROR: bad" : falseFour of six matched, including pre-ERROR where the text is buried in the middle of a token. The last line is the contrast: eq demands the whole string be identical, and says false.
This default is the right one for log scanning — you almost never know what surrounds the thing you are hunting. But it is also the source of the classic miscount, where a script looking for ERROR reports a line that says NO_ERROR as an error. Keep it in mind; Chapter 11.8's anchors and word boundaries exist precisely to narrow this down when you need it narrowed.
3. Case Sensitivity and the /i Modifier
Since case already cost us a match in section one, here is the switch.
use strict;
use warnings;
my @subjects = ("ERROR", "error", "Error", "eRrOr");
printf "%-10s %-10s %s\n", "SUBJECT", "/error/", "/error/i";
for my $s (@subjects) {
printf "%-10s %-10s %s\n", $s,
($s =~ /error/ ? "match" : "-"),
($s =~ /error/i ? "match" : "-");
}SUBJECT /error/ /error/i
ERROR - match
error match match
Error - match
eRrOr - matchA letter after the closing slash is a modifier, and /i makes the whole pattern case-insensitive. One of four matched without it; four of four with it.
Use it when you genuinely do not know the tool's capitalisation, which in EDA log parsing is often. Avoid it when you do know, because /i also makes Error and ERROR indistinguishable in output you may later need to tell apart — some tools use the case to signal severity.
4. What a Match Actually Returns
This is the section to read twice. The match operator returns four different things.
use strict;
use warnings;
my $line = "slack -0.12";
# ---------- scalar context ----------
my $hit = ($line =~ /slack/);
my $miss = ($line =~ /ERROR/);
printf "success -> [%s] defined:%s true:%s\n",
$hit, (defined $hit ? "y" : "n"), ($hit ? "y" : "n");
printf "failure -> [%s] defined:%s true:%s\n",
$miss, (defined $miss ? "y" : "n"), ($miss ? "y" : "n");
# ---------- list context, NO capture groups ----------
my @a = ($line =~ /slack/);
printf "list, no captures, match : %d item(s) [%s]\n", scalar @a, join("|", @a);
my @b = ($line =~ /ERROR/);
printf "list, no captures, no match : %d item(s) [%s]\n", scalar @b, join("|", @b);
# ---------- list context, WITH capture groups ----------
my @c = ($line =~ /(\w+)\s+(\S+)/);
printf "list, 2 captures, match : %d item(s) [%s]\n", scalar @c, join("|", @c);
my @d = ($line =~ /(\w+)\s+(\S+)\s+(\w+)/);
printf "list, 3 captures, no match : %d item(s) [%s]\n", scalar @d, join("|", @d);success -> [1] defined:y true:y
failure -> [] defined:y true:n
list, no captures, match : 1 item(s) [1]
list, no captures, no match : 0 item(s) []
list, 2 captures, match : 2 item(s) [slack|-0.12]
list, 3 captures, no match : 0 item(s) []Read the six lines as a table of four behaviours.
Scalar context, success: 1. Not the matched text. The number one.
Scalar context, failure: the empty string — and it is defined. The defined:y on that line is the fact to retain. A match never returns undef, so defined($line =~ /x/) is always true and tests nothing at all. If you want to know whether the match succeeded, test it directly.
List context with no capture groups: the one-element list (1) on success, the empty list on failure. This is the shape almost nobody predicts. A successful match with nothing to capture still has to report success, and in list context it does that by handing back a single 1. So my @r = ($line =~ /slack/); gives you an array of length 1 containing the number 1 — which is useless as data but perfectly usable as a truth test, because an empty list is false and a one-element list is true.
List context with capture groups: the captured parts on success, the empty list on failure. The pattern with two groups returned slack and -0.12. The pattern with three groups could not match at all, so it returned nothing — not three undef values. That matters: the length of the returned list tells you whether the match worked, not how many groups the pattern has.
5. The Mistake Everyone Makes Once
Put the two scalar-context and list-context rules together and the most common beginner bug in Perl falls out.
use strict;
use warnings;
my $line = "ERROR: bad";
# WRONG: a match in scalar context, assigned to a scalar, is 1 or "" --
# never the matched text.
my $scalar_result = ($line =~ /(\w+)/);
printf "my \$x = (\$line =~ /(\\w+)/) -> [%s]\n", $scalar_result;
# RIGHT: list context, so the capture comes out.
my ($list_result) = ($line =~ /(\w+)/);
printf "my (\$x) = (\$line =~ /(\\w+)/) -> [%s]\n", $list_result;
print "\nthe parentheses around \$x are the whole difference\n";my $x = ($line =~ /(\w+)/) -> [1]
my ($x) = ($line =~ /(\w+)/) -> [ERROR]
the parentheses around $x are the whole differenceThe two statements differ by two characters. The first assigns to a scalar, which puts the match in scalar context, so it returns 1 and the capture group is simply ignored. The second assigns to a one-element list, which puts the match in list context, so the capture comes out.
What makes this bug expensive is that 1 is a plausible-looking value. A script that prints found 1 or writes 1 into a report looks like it is working. Under use warnings you get no complaint, because nothing invalid happened — you asked for a boolean and you got one.
The habit that avoids it: whenever a pattern has parentheses in it, the thing you assign to should have parentheses too.
6. A Bare Pattern Tests $_
A pattern needs something to match against. If you do not bind one with =~, Perl uses $_.
use strict;
use warnings;
my @lines = ("slack -0.12", "clean", "slack 0.44");
# A pattern with nothing bound to it tests $_
for (@lines) {
printf "%-14s -> %s\n", "[$_]", (/slack/ ? "match" : "no match");
}
print "\n";
# grep and map set $_ too, which is why this reads so compactly
my @slack_lines = grep { /slack/ } @lines;
printf "grep { /slack/ } found %d line(s): %s\n",
scalar @slack_lines, join(", ", @slack_lines);[slack -0.12] -> match
[clean] -> no match
[slack 0.44] -> match
grep { /slack/ } found 2 line(s): slack -0.12, slack 0.44This is the feature that makes Perl's text handling as terse as it is. A for loop with no loop variable sets $_; grep and map set $_; reading from a filehandle in a while loop can set $_. In every one of those places a bare /pattern/ is complete and reads almost like English — grep { /slack/ } @lines needs no explanation at all.
Chapter 9.7 covered $_ itself and the scoping rules that keep these uses from interfering with each other.
7. The Cost of That Convenience
The same default has a failure mode, and it is quiet.
use strict;
use warnings;
my $line = "ERROR: setup violation";
# Looks like it tests $line. It does not -- it tests $_, which is undef here.
my $count = 0;
{
no warnings 'uninitialized';
$count++ if /ERROR/;
}
printf "bare /ERROR/ while checking \$line : count = %d\n", $count;
# The same test, bound properly
my $bound = 0;
$bound++ if $line =~ /ERROR/;
printf "\$line =~ /ERROR/ : count = %d\n", $bound;bare /ERROR/ while checking $line : count = 0
$line =~ /ERROR/ : count = 1The bare pattern counted zero errors on a line that plainly contains one, because it never looked at $line — it looked at $_, which nothing had set.
Two things to note about how that was demonstrated. The no warnings 'uninitialized' block is there so the page can show you the count rather than a warning; delete it and the run prints Use of uninitialized value $_ in pattern match to stderr instead. So use warnings does catch this particular case, and that is a good argument for always enabling it. But it catches it only because $_ happened to be undefined. Inside a for (@lines) loop, or after a while loop that set $_, a stray bare pattern silently tests the wrong variable and warns about nothing.
8. The Leading m and Other Delimiters
The operator's real name is m, for match. Between slashes you may leave it out; with any other delimiter you may not.
use strict;
use warnings;
my $path = "/proj/lib/and2.lib";
# With slashes, the leading m is optional
printf "// : %s\n", ($path =~ /and2/ ? "match" : "no match");
printf "m// : %s\n", ($path =~ m/and2/ ? "match" : "no match");
# With any other delimiter, m is REQUIRED
printf "m{} : %s\n", ($path =~ m{and2} ? "match" : "no match");
printf "m() : %s\n", ($path =~ m(and2) ? "match" : "no match");
printf "m## : %s\n", ($path =~ m#and2# ? "match" : "no match");// : match
m// : match
m{} : match
m() : match
m## : matchAll five are the same match. In practice you will write /.../ for short patterns and m{...} whenever the pattern contains a slash, for the reason Chapter 11.1 gave: a path written with escaped delimiters is much harder to read than the path itself.
9. What To Remember
- A pattern between slashes is a contains test, not an equality test, and it matches anywhere in the string — including inside a word.
- Matching is case-sensitive by default.
/iturns that off for the whole pattern. - Scalar context:
1on success,""on failure. The failure value is false but defined, sodefined($s =~ /x/)tests nothing. - List context with no capture groups:
(1)on success,()on failure. A one-element list containing the number one. - List context with capture groups: the captures on success,
()on failure — never a list ofundefs. The list's length tells you whether the match worked. - If the pattern has parentheses, the assignment needs parentheses.
my $x = (...)gives1;my ($x) = (...)gives the captured text. - A bare pattern tests
$_. Excellent insidefor,grepandmap; a silent bug anywhere else. mis optional with slashes, required with every other delimiter.
Chapter 11.3 takes the binding operator itself — what =~ really does, its negated form !~, and why its precedence lets you write a match inside a larger expression without parentheses.
Where this fits
Part of the Perl curriculum.
