Skip to content
Regex Deep Dive
step 1/5

Reading — step 1 of 5

Learn

~2 min readReal-World Perl

Perl's regex went far beyond what other languages had — and other languages copied. PCRE (Perl-Compatible Regular Expressions) is the de-facto standard, used by Python re, JavaScript, .NET, Java's regex.

Anchors and assertions:

  • ^ start of string (or line in /m mode)
  • $ end of string (or line)
  • \b word boundary
  • \B non-word-boundary
  • \A absolute start (ignores /m)
  • \Z absolute end (allows trailing \n)
  • \z absolute end (no trailing newline)

Character classes:

  • \d digit, \D non-digit
  • \s whitespace, \S non-whitespace
  • \w word char [A-Za-z0-9_], \W non-word
  • [abc] any of, [^abc] none of
  • [a-z] range

Quantifiers:

  • * 0+
  • + 1+
  • ? 0 or 1
  • {n} exactly n
  • {n,m} n to m
  • {n,} n+
  • Add ? for non-greedy: *?, +?, ??

Greedy vs non-greedy — biggest source of bugs:

"<b>bold</b> and <i>italic</i>" =~ /<.+>/;       # matches "<b>bold</b> and <i>italic</i>"
"<b>bold</b> and <i>italic</i>" =~ /<.+?>/;      # matches "<b>" only

Capture groups:

my $date = "2026-05-08";
my ($y, $m, $d) = $date =~ /(\d{4})-(\d{2})-(\d{2})/;

Named captures(?<name>...):

if ("ada@x.io" =~ /(?<user>\w+)@(?<domain>[\w.]+)/) {
    print "$+{user} at $+{domain}\n";
}

Non-capturing group(?:...):

/(?:foo|bar) baz/   # group for alternation, not captured

Lookahead/lookbehind — zero-width assertions:

  • (?=...) positive lookahead — "followed by"
  • (?!...) negative lookahead — "NOT followed by"
  • (?<=...) positive lookbehind — "preceded by"
  • (?<!...) negative lookbehind — "NOT preceded by"
# match a word followed by 'ed' but exclude 'ed'
"jumped over" =~ /\w+(?=ed)/;     # captures "jump"

# match number not preceded by '$'
"price: 5, qty: $10" =~ /(?<!\$)\d+/g;     # 5 only

Modifiers:

  • i case-insensitive
  • g global (find all)
  • m multiline (^/$ per line)
  • s dot matches newline
  • x extended — allow whitespace and comments inside pattern

/x for readable regex:

if ($email =~ /
    ^
    (\w+)              # local part
    @
    ([\w.-]+)          # domain
    $
/x) { ... }

Substitution variants:

  • s/old/new/ — first occurrence
  • s/old/new/g — all occurrences
  • s/old/new/r — return new string, don't modify
  • s/(.+)/uc $1/e/e evaluates replacement as Perl code
my $upper = $s =~ s/.+/uc $&/er;     # /e and /r combined

Useful tricks:

  • tr/a-z/A-Z/ — fast char translation (NOT regex)
  • =~ /(\d+)/g in list context returns ALL matches: my @nums = $s =~ /(\d+)/g;
  • pos($s) returns where the next /g will start

Perl regex is a tool you grow into. Real systems use it for parsing, validation, normalization, search-replace at the boundary of structured and unstructured data.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…