Adding a couple of useful extensions to the String type in Dart, to find if a string contains another string more than once.
I recently came upon this issue while working on Shortcut Keeper, my Flutter desktop app.
I needed to find a way to check if a string like “Command-K Command-T” had the substring “Command” more than once, and if so, from which index did the second occurrence of the substring begin.
To solve this, I ended up writing a couple of simple extension methods to Dart’s String type, which can be useful for anyone facing this issue!
The general issue
In other words, we need to find:
1) If a string contains another string (stringToFind
) more than once, and
2) The index
where this second occurrence can be found.
We can then further extend this to be able to potentially find the locations of the nth occurrence of stringToFind
.
Of course, we could also solve this with regular expressions (via Dart’s RegExp class), but I prefer the more readable way presented here.
Solution
Finding the second occurrence of a substring
The extension I ended up with is a pretty straightforward one:
extension SecondOccurenceOfSubstring on String { int secondIndexOf(String stringToFind) { if (indexOf(stringToFind) == -1) return -1; return indexOf(stringToFind, indexOf(stringToFind) + 1); } bool hasSecondOccurence(String stringToFind) { return secondIndexOf(stringToFind) != -1; } }
Here, we take advantage of the second optional parameter (start
) of the indexOf
method from Dart’s core library, to set from where to begin searching for the string. If the string is not found, we return the conventional -1.
The hasSecondOccurence
method is a convenient way to check if a substring appears more than once in the provided string.
We can then simply use it like this:
String s1 = "Command-K Command-T"; s1.secondIndexOf("Command"); // Returns 10 s1.hasSecondOccurence("Command"); // Returns true s1.secondIndexOf("Control"); // Returns -1 s1.hasSecondOccurence("Control"); // Returns false String s2 = "Give it away give it away give it away now"; s2.secondIndexOf("away"); // Returns 21
This works great, so we can go one step further and build a more general extension, for finding the location of any occurrence of a substring in a string.
Finding the nth occurrence of a substring
Now, we want to provide a method, such that we can find, for example, the index of the fourth (n = 4) occurrence of a substring in a string:
String s3 = "Give it away give it away give it away give it away give it away now"; s3.nThIndexOf("away", 4); // Returns 47
In the above example, the fourth "away"
substring can be found after 47 characters in our provided string s3
.
We can use this extension to do that:
extension NthOccurrenceOfSubstring on String { int nThIndexOf(String stringToFind, int n) { if (indexOf(stringToFind) == -1) return -1; if (n == 1) return indexOf(stringToFind); int subIndex = -1; while (n > 0) { subIndex = indexOf(stringToFind, subIndex + 1); n -= 1; } return subIndex; } bool hasNthOccurrence(String stringToFind, int n) { return nThIndexOf(stringToFind, n) != -1; } }
Again, we apply the same strategy as above, with the indexOf
method, to move closer each time to the nth occurrence that we want. To help with understanding, this is what happens in the nThIndexOf
method when we call it with n = 4
:

Here are some more examples using this extension:
String s3 = "Give it away give it away give it away give it away give it away now"; s3.nThIndexOf("away", 2); // Returns 21 s3.nThIndexOf("away", 3); // Returns 34 s3.nThIndexOf("away", 4); // Returns 47 s3.nThIndexOf("away", 5); // Returns 60 s3.nThIndexOf("away", 6); // Returns -1 s3.hasNthOccurrence("away", 3); // true, we can find "away" at least 3 times in the string s3.hasNthOccurrence("away", 6); // false, we cannot find a 6th occurrence of "away" in the string
We can now use these string extensions easily anywhere we need this kind of functionality in our Dart code.
Hope this small tip was helpful!