Regex tester · Guide
Regex Match Count: Counting Occurrences and Testing Containment
Counting matches and checking whether a match exists are different operations with different costs. Counting also has a failure mode that testing does not: a pattern that can match nothing at all.
Counting
// JavaScript — g flag required
(str.match(/\d+/g) || []).length;
[...str.matchAll(/\d+/g)].length;
# Python
len(re.findall(r'\d+', s))
# PHP
preg_match_all('/\d+/', $s); // returns the count
# shell — -o prints each match on its own line
grep -o '[0-9]\+' file | wc -l
grep -c 'pattern' file # counts LINES, not matchesgrep -c counting lines rather than matches is a classic discrepancy — a line with three matches counts once.
Containment is cheaper
To answer "does this contain a match", use test or search. They stop at the first hit; counting scans the entire input. On large strings in a hot path that difference is real.
It also expresses intent. if (count > 0) and if (test(...)) behave the same and read differently — the second says what you meant.
The zero-width trap
A pattern that can match an empty string — \d*, a?, ^ — matches at every position, so counts are surprising and manual loops hang:
'abc'.match(/\d*/g) // ['', '', '', ''] — four empty matchesIf you write your own exec loop with the g flag, a zero-width match never advances lastIndex and the loop runs forever. matchAll handles this internally; hand-rolled loops must bump lastIndex themselves.
The fix is usually the pattern: require at least one character with + instead of *.
Overlapping matches
Standard matching does not overlap: after a match the engine resumes at its end, so aa in aaaa counts twice, not three times.
To count overlapping occurrences, use a lookahead that consumes nothing — (?=(aa)) — and count the captures. Each position is tested independently, so aaaa gives three.
Frequently asked questions
Why does grep -c give a smaller number than expected?
It counts matching lines, not matches. Use grep -o piped to wc -l.
Why does my count include empty strings?
The pattern can match zero characters. Use + instead of * where a match must consume something.
Should I count matches to test containment?
No. Use test or search — they stop at the first match.
Ready to try it?
Open the free browser-based Regex tester and apply what you just read — no sign-up, runs locally.
Open the Regex tester tool