How to Count Occurrences of a Substring in a String in PowerShell

To count occurrences of a substring in a string in PowerShell, escape the substring and count the regex matches. This one line returns how many times $find appears in $text:

[regex]::Matches($text, [regex]::Escape($find)).Count

The count you get depends on case, special characters and overlaps, and a few popular shortcuts quietly get it wrong. I ran each method below in PowerShell 7 and Windows PowerShell 5.1 and noted where they disagree.

Count a substring with [regex]::Matches

Matches returns one object per hit, so its Count property is your answer. It’s case-sensitive by default, and the IgnoreCase option changes that:

$text = 'Austin, Denver, austin, Seattle, AUSTIN'
$find = 'Austin'

"Case sensitive:   $([regex]::Matches($text, $find).Count)"
"Case insensitive: $([regex]::Matches($text, $find, 'IgnoreCase').Count)"

Output:

Case sensitive:   1
Case insensitive: 3
PowerShell count substring occurrences with regex Matches
Case-sensitive and case-insensitive counts of Austin (PowerShell 7)

Only one “Austin” matches exactly, while all three match when case is ignored. If you only need a yes-or-no answer, check whether a string contains a substring instead of counting.

Why escape the substring before counting?

Matches treats your text as a regular expression. A dot means “any character”, and a plus sign is a quantifier, so plain text can count the wrong things or throw:

$text = 'Version 1.0 shipped, 1x0 is a typo, 1.0 again'

"Without Escape: $([regex]::Matches($text, '1.0').Count)"
"With Escape:    $([regex]::Matches($text, [regex]::Escape('1.0')).Count)"
try { [regex]::Matches('C++ and C++', 'C++').Count }
catch { "Failed. $($_.Exception.InnerException.Message)" }

Output:

Without Escape: 3
With Escape:    2
Failed. Invalid pattern 'C++' at offset 3. Nested quantifier '+'.

Without escaping, 1.0 also matched the typo 1×0. Searching for C++ fails in both shells, but the message differs: PowerShell 7 says “Invalid pattern ‘C++’ at offset 3”, and Windows PowerShell 5.1 says “parsing “C++” – Nested quantifier +”.

[regex]::Escape fixes both. More ways to handle these characters are in escaping special characters in PowerShell.

Count occurrences with the -split operator

Splitting on the substring gives one more piece than there are matches, so subtract one. The -split operator ignores case, and -csplit doesn’t:

$text = 'Austin, Denver, austin, Seattle, AUSTIN'
"-split:  $(($text -split 'Austin').Count - 1)"
"-csplit: $(($text -csplit 'Austin').Count - 1)"

$formula = 'f(x) + g(x)'
"Regex (x):   $(($formula -split '(x)').Count - 1)"
"SimpleMatch: $(($formula -split '(x)', 0, 'SimpleMatch').Count - 1)"

Output:

-split:  3
-csplit: 1
Regex (x):   4
SimpleMatch: 2

The last two lines show the trap. The -split delimiter is a regex too, and parentheses make it keep a captured x in the output, so the count jumps from 2 to 4.

The SimpleMatch option treats the delimiter as plain text, but it only works when you also pass the max-substrings value, 0 for all.

Edge matches still count right, since -split returns empt