Troubleshooting
"It matches too much"
Almost always greedy quantifiers. ".*" on "hi" and "bye"
matches the whole "hi" and "bye". Fix: lazy — ".*?". (See
Quantifiers.) If it still over-matches, your
"anything" is too permissive: [^"]* ("not a quote") is more
precise than .*? for quoted strings.
"It matches inside words"
You forgot \b. cat matches concatenate; \bcat\b doesn't.
(See Anchors.)
"It doesn't match and I can't see why"
- Print the pattern. Actually look at it — is that
\.or.? Is the raw string prefix there? - Bisect it. Test halves: does
\d{4}match? Does\d{4}-\d{2}? The half that fails contains the bug. - Paste it into regex101.com. It explains each token and shows the match step-by-step. This solves most mysteries in seconds.
- Check the flags. Multiline text needs
re.MULTILINEfor^; case differences needre.IGNORECASE.
"No match" from findall with groups
findall returns groups, not whole matches, when the pattern has
capturing groups. You got [('2026','10','13')] and wanted
['2026-10-13']. Fix: (?:...) for groups you don't need to keep.
(See Groups.)
Catastrophic backtracking: the freeze
Your program hangs on a 50-character string. The pattern has nested
quantifiers — (a+)+, (\w+\s*)+ — and the engine tries
exponential combinations. Fixes, in order:
- Be specific.
[^"]*instead of.*?;\d+instead of(\d+)+. - Use possessive/atomic groups if your flavor has them
(
(?>...)in PCRE/Java) — they forbid backtracking into the group. - Don't regex it. If the pattern needs nesting, that's the parser signal from chapter 1.
"Works in the tester, fails in my code"
- Double escaping. In JSON/Java strings,
"\\d"is needed to get\dto the engine. The tester took your pattern raw; your code's string layer ate a backslash. Print the pattern your code actually compiles. - Different flavor. The tester defaulted to PCRE; you're running Python/JavaScript. Check the flavors table — lookbehind and named-group syntax are the usual culprits.
- find vs. matches. Java's
matches()requires full-string match (likefullmatch);find()scans. Python'ssearchvsfullmatch— same trap, different names.
The debugging mantra
Smallest failing input. Fewest pattern pieces. One change at a time. Regex rewards the same method as everything else — it just punishes guessing harder.
Next: Glossary