Programming
String Manipulation
Coding Tutorial
Text Analysis
Programming Languages

How to count string occurrence in string?

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

Counting how many times one string appears inside another sounds simple, but you need to decide what counts as an occurrence. The biggest distinction is whether matches may overlap. Once that is clear, the implementation becomes straightforward.

Non-Overlapping Matches

In many languages, the default helper counts non-overlapping occurrences. In Python, that is str.count().

python
text = "hello world, hello universe, hello galaxy"
count = text.count("hello")
print(count)

Output:

text
3

This is the right default when you are counting separate literal substring occurrences.

Overlapping Matches

The tricky case is overlap. In "ababa", the substring "aba" appears twice if overlapping matches are allowed:

  • positions 0-2
  • positions 2-4

But Python's count() returns only one because it counts non-overlapping matches.

python
text = "ababa"
print(text.count("aba"))

If you need overlaps, use a sliding window or a regex lookahead.

python
1def count_overlapping(text: str, sub: str) -> int:
2    total = 0
3    for i in range(len(text) - len(sub) + 1):
4        if text[i:i + len(sub)] == sub:
5            total += 1
6    return total
7
8print(count_overlapping("ababa", "aba"))

This returns 2, which is the overlapping count.

Regex Lookahead for Overlap

A regular expression lookahead is another clean solution when overlap matters.

python
1import re
2
3text = "ababa"
4matches = re.findall(r"(?=(aba))", text)
5print(len(matches))

The lookahead does not consume characters, so later matches can start inside earlier ones.

JavaScript Example

JavaScript does not provide a simple built-in string count method, but for literal text you can still count non-overlapping occurrences.

javascript
const text = "hello world, hello universe, hello galaxy";
const count = text.split("hello").length - 1;
console.log(count);

For pattern-based counting, regex is often more appropriate:

javascript
const text = "cat bat cat rat";
const matches = text.match(/cat/g) || [];
console.log(matches.length);

Case Sensitivity

Substring counting is usually case-sensitive by default. If you want case-insensitive matching, normalize first.

python
text = "Hello hello HELLO"
count = text.lower().count("hello")
print(count)

Be explicit about this choice. Do not assume the language is doing case-insensitive comparison automatically.

Literal Text Versus Pattern Matching

A plain substring count and a regex count answer slightly different questions:

  • substring count asks whether a literal sequence appears
  • regex count asks whether a pattern matches

If the target is fixed literal text, use the simpler literal approach first. Regex is more powerful, but it adds escaping rules and extra complexity.

Java Example

In Java, a common non-overlapping approach is to move through the string with indexOf.

java
1public static int countOccurrences(String text, String sub) {
2    int count = 0;
3    int index = 0;
4
5    while ((index = text.indexOf(sub, index)) != -1) {
6        count++;
7        index += sub.length();
8    }
9
10    return count;
11}

This follows the same non-overlapping rule as many built-in helpers in other languages.

Word Counting Is Different

Another common mistake is confusing substring counting with word counting. If you count "he" inside "the theater", you are counting substrings, not whole words.

Whole-word counting usually needs tokenization or regex boundaries, not a simple substring helper.

So before implementing the code, clarify whether you want:

  • literal substring matches
  • overlapping substring matches
  • whole-word matches
  • case-insensitive matches

Common Pitfalls

Assuming built-in count helpers include overlapping matches is the biggest source of incorrect results.

Forgetting case sensitivity can make counts seem wrong even when the code is behaving correctly.

Using regex for simple literal counts makes the solution harder than necessary.

Counting substrings when the real requirement is whole-word matching leads to subtly incorrect output.

Summary

  • Built-in helpers usually count non-overlapping literal matches.
  • Overlapping matches need a sliding window or a regex lookahead.
  • Case sensitivity should be handled intentionally.
  • Regex is useful for patterns, but not always necessary for plain text.
  • Define what counts as an occurrence before choosing the implementation.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.