How can I count the number of times a particular string occurs in another string?
There are multiple ways to count occurrences of a substring within a larger string. Common approaches in JavaScript include:
- Looping with
indexOf()orsearch()in a while loop until you no longer find matches. - Regular expressions with
match(),matchAll()(ES2020+), or a repeatedexec()loop to find multiple occurrences.
Below are a few detailed examples and considerations.
1. Looping with indexOf() in JavaScript
function countOccurrences(str, subStr) { let count = 0; let position = 0; while (true) { // Find subStr starting from position const foundPos = str.indexOf(subStr, position); if (foundPos === -1) { break; // no more matches } count++; // Move position past the last found index position = foundPos + subStr.length; } return count; } console.log(countOccurrences("ababab", "ab")); // 3 console.log(countOccurrences("hello world", "o")); // 2
indexOf(subStr, fromIndex)returns the index wheresubStris found (or-1if none).- We increment
counteach time, then movepositionforward past the substring to find subsequent matches. - This approach finds non-overlapping occurrences.
Overlapping Occurrences?
- If you need to count overlapping occurrences (e.g.,
"aaaa"has 3 overlapping occurrences of"aa"), you’d shiftpositionby 1 instead ofsubStr.length:position = foundPos + 1;
2. Using a Regular Expression
2.1 String.prototype.match() (Non-Overlapping)
function countOccurrencesRegex(str, subStr) { // Escape any special regex characters in subStr if needed: const escapedSubStr = subStr.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // Create a "global" RegExp const pattern = new RegExp(escapedSubStr, 'g'); // str.match(pattern) returns an array of matches, or null if none const matches = str.match(pattern); return matches ? matches.length : 0; } console.log(countOccurrencesRegex("ababab", "ab")); // 3 console.log(countOccurrencesRegex("hello world", "o")); // 2
- This also doesn’t handle overlapping matches by default because a global regex proceeds past the matched substring.
2.2 Counting Overlapping Occurrences with RegExp.prototype.exec()
Overlapping can be handled by manually iterating:
function countOverlapping(str, subStr) { // Escape if subStr might have special regex characters const escapedSubStr = subStr.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // 'g' for multiple matches; we manually manage lastIndex for overlaps const pattern = new RegExp(escapedSubStr, 'g'); let count = 0; let match; while ((match = pattern.exec(str)) !== null) { count++; // Manually reset the regex 'lastIndex' to allow overlapping pattern.lastIndex = match.index + 1; } return count; } console.log(countOverlapping("aaaa", "aa")); // 3
- After each match, we shift
pattern.lastIndexby 1 (instead ofmatch.index + subStr.length) so the next search can catch overlapping occurrences.
2.3 ES2020+ matchAll()
Modern JavaScript also has String.prototype.matchAll(), which returns an iterator of match objects (including capturing groups). You can loop over them and count. However, handling overlaps still requires a workaround similar to the exec() approach.
function countMatchesWithMatchAll(str, subStr) { const escapedSubStr = subStr.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const pattern = new RegExp(escapedSubStr, 'g'); // matchAll returns an iterator of match results return [...str.matchAll(pattern)].length; } console.log(countMatchesWithMatchAll("ababab", "ab")); // 3
Still non-overlapping by default—overlapping requires manual resets, which typically means you go back to a custom loop.
3. Other Languages or Approaches
- Many languages (e.g., Python) have similar methods or libraries to count substrings.
- If you just need to see if a substring occurs at all,
String.includes()orindexOf(subStr) !== -1suffices (in JavaScript). - For large or complex tasks (like searching big logs or entire files), more advanced or memory-efficient solutions may be needed.
Best Practices
- Escape your Substring if it might contain special regex characters (like
*,+,., etc.). Otherwise, your pattern can break or match unintended strings. - Overlapping vs Non-Overlapping: Clarify whether you need overlapping matches. The logic or method changes slightly.
- Performance: For very large strings or repetitive tasks, consider efficiency. But for typical use cases, these examples are sufficient.
Final Thoughts
To count occurrences of a substring in JavaScript (or any language):
- Use a loop with
indexOf()orsearch(), adjusting the start index each time a match is found. - Or use regex (
match(),exec(),matchAll()) with a global flag. - For overlapping occurrences, you must manually adjust how far the search index advances.
Bonus: Level Up Your JavaScript & Coding Interview Skills
If you’re exploring string manipulation and want to sharpen your JavaScript fundamentals or coding interview capabilities, check out these DesignGurus.io courses:
-
Grokking JavaScript Fundamentals
Deepen your understanding of closures, prototypes, async/await, and more. -
Grokking the Coding Interview: Patterns for Coding Questions
Master pattern-based problem-solving—useful for both interview prep and real-world dev tasks.
For hands-on feedback, explore Mock Interviews (Coding Mock Interview or System Design Mock Interview) with ex-FAANG engineers. Also, visit the DesignGurus.io YouTube channel for free tutorials on coding patterns, system design, and more.
Summary: Use a while loop with indexOf(), or a regex approach (test(), match(), exec(), matchAll()) to count occurrences. Decide if you need overlapping matches and adjust your strategy accordingly.