Finding all positions of substring in a larger string in C
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In C#, the usual way to find every position of a substring is to call IndexOf in a loop and keep moving the starting index forward. The key detail is deciding whether matches are allowed to overlap, because that changes how far the next search should advance.
The Basic IndexOf Loop
For ordinary non-overlapping matches, the algorithm is straightforward:
This prints 0, 4, 8. After each match, the next search begins after the matched substring.
Handling Overlapping Matches
If overlapping matches matter, move the starting position by one character instead of by the pattern length.
This prints 0, 2, which is correct for overlapping occurrences.
Be Explicit About Comparison Rules
IndexOf has overloads that let you choose comparison behavior. That matters because text matching can be case-sensitive, case-insensitive, ordinal, or culture-aware.
For technical text such as identifiers, protocol values, or file formats, StringComparison.Ordinal is usually the safest choice. For case-insensitive technical matching, use StringComparison.OrdinalIgnoreCase.
Being explicit avoids surprises and makes the method contract easier to understand.
Returning an Iterator Instead of a List
If you want lazy consumption of the results, yield return is a nice alternative to building a list up front.
This is useful when callers want to process matches as they are found instead of storing all positions immediately.
When Regex Is the Wrong Tool
If you are searching for a literal substring, regular expressions are often unnecessary. Regex adds power when the pattern itself is variable or rule-based, but it also adds escaping rules and more complexity.
For example, this is a valid regex search:
But if the goal is simply "find every occurrence of cat," IndexOf is clearer and usually the better tool.
Common Pitfalls
The biggest mistake is forgetting to define whether overlaps count. start = index + pattern.Length and start = index + 1 produce different answers, and both can be correct depending on the requirement.
Another issue is leaving StringComparison implicit. That makes the method behavior less obvious and can cause unexpected casing or culture behavior.
Developers also forget to guard against an empty pattern. Without that check, the loop logic can become ambiguous or even infinite.
Finally, do not overuse regex for simple literal searches. It solves a broader problem and is harder to reason about when plain IndexOf already matches the requirement.
Summary
- Loop with
IndexOfto find all substring positions in C#. - Advance by
pattern.Lengthfor non-overlapping matches. - Advance by
1for overlapping matches. - Specify
StringComparisonexplicitly so the matching rule is clear. - Guard against empty patterns before entering the search loop.

