In this article we will discuss how to find all occurrences / Positions of a sub string in a given string in both case sensitive & case insensitive manner.

Find All Case Sensitive Occurrences of a Sub String in a given String

Logic:

Use std::string::find to search the first occurrence and then go on searching using same logic from that position onward, till you reach the end.

Complete example is as follows,

#include <iostream>
#include <string>
#include <algorithm>

/*
 *Find all positions of the a SubString in given String
 */
void findAllOccurances(std::vector<size_t> & vec, std::string data, std::string toSearch)
{
	// Get the first occurrence
	size_t pos = data.find(toSearch);

	// Repeat till end is reached
	while( pos != std::string::npos)
	{
		// Add position to the vector
		vec.push_back(pos);

		// Get the next occurrence from the current position
		pos =data.find(toSearch, pos + toSearch.size());
	}
}

int main()
{
	std::string data = "Hi this is a Sample string, 'iS' is here 3 times";

	std::vector<size_t> vec;

	// Get All occurrences of the 'is' in the vector 'vec'
	findAllOccurances(vec, data , "is");

	std::cout<<"All Index Position of 'is' in given string are,"<<std::endl;

	for(size_t pos : vec)
		std::cout<<pos<<std::endl;


	return 0;
}

Output:
All Index Position of 'is' in given string are,
5
8
33

As it’s internally using std::string::find to the sub string therefore it is case sensitive and able to find 3 occurrences only.

Find All Case Sensitive occurrence of a Sub String in a given String

We will use the same logic as above i.e. keep on search the occurrences of sub string till reaches the end.
But to find an occurrence of sub string, we will use customized case insensitive version of std::string::find .

Checkout the complete code as follows,

#include <iostream>
#include <string>
#include <algorithm>
// Case Insensitive version of std::string::find
size_t findCaseInsensitive(std::string data, std::string toSearch, size_t pos = 0)
{
	// Convert String to lower case
	std::transform(data.begin(), data.end(), data.begin(), ::tolower);
	// Convert String to lower case
	std::transform(toSearch.begin(), toSearch.end(), toSearch.begin(), ::tolower);
	return data.find(toSearch, pos);
}

/*
 *Find all positions of the a Case Insensitive Sub String in given String
 */
void findAllOccurancesCaseInsensitive(std::vector<size_t> & vec, std::string data, std::string toSearch)
{
	// Find First Position
	size_t pos = findCaseInsensitive(data,toSearch);
	// Iterate till end
	while( pos != std::string::npos)
	{
		// Push position in vector
		vec.push_back(pos);
		// Search next position
		pos = findCaseInsensitive(data,toSearch, pos + toSearch.size());
	}
}

int main()
{
	std::string data = "Hi this is a Sample string, 'iS' is here 4 times";

	std::vector<size_t> vec;

	// Get All case insensitive occurrences of the 'is' in the vector 'vec'
	findAllOccurancesCaseInsensitive(vec, data , "IS");

	std::cout<<"All Index Position of 'is' in given string are,"<<std::endl;

	for(size_t pos : vec)
		std::cout<<pos<<std::endl;


	return 0;
}

Output:
All Index Position of 'is' in given string are,
5
8
29
33

 

Because we are using case insensitive version of std::string::find, therefore we will get 4 reparations of sub string.

Generic Find All Implementation

We don’t need to maintain 2 separate functions to find all occurrences, we can create a generic find_all function, that will accept String Finder function as callback and use it to find repeated occurrences of sub strings i.e.

typedef size_t (* FINDFUNCTOR)(std::string data, std::string toSearch, size_t pos);

void findAllOccurances(std::vector<size_t> & vec, std::string data, std::string toSearch, FINDFUNCTOR finder)
{
	// Find first occurrence
	size_t pos = finder(data, toSearch, 0);

	// Iterate till last
	while( pos != std::string::npos)
	{
		vec.push_back(pos);
		// Find next occurrence
		pos =finder(data, toSearch, pos + toSearch.size());
	}
}

Let’s use this above function to find case insensitive substrings by passing findCaseInsensitive as callback
// Find All case insensitive occurrences of the 'is' in the vector 'vec'
findAllOccurances(vec, data , "iS", &findCaseInsensitive);

Let’s use this above function to find case sensitive substrings by passing std::string::find as callback i.e.
// Get All Case Sensitive occurrences of the 'is' in the vector 'vec'
findAllOccurances(vec, data , "iS", [&](std::string data, std::string toSearch, size_t pos){
	return data.find(toSearch, pos);
});

Complete example is as follows,
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>

// Case Insensitive version of std::string::find
size_t findCaseInsensitive(std::string data, std::string toSearch, size_t pos = 0)
{
	// Convert String to lower case
	std::transform(data.begin(), data.end(), data.begin(), ::tolower);
	// Convert String to lower case
	std::transform(toSearch.begin(), toSearch.end(), toSearch.begin(), ::tolower);
	return data.find(toSearch, pos);
}


typedef size_t (* FINDFUNCTOR)(std::string data, std::string toSearch, size_t pos);

void findAllOccurances(std::vector<size_t> & vec, std::string data, std::string toSearch, FINDFUNCTOR finder)
{
	// Find first occurrence
	size_t pos = finder(data, toSearch, 0);

	// Iterate till last
	while( pos != std::string::npos)
	{
		vec.push_back(pos);
		// Find next occurrence
		pos =finder(data, toSearch, pos + toSearch.size());
	}
}

int main()
{
	std::string data = "Hi this is a Sample string, iS is 3 times here";

	std::vector<size_t> vec;

	std::cout<<"All Index Position of Case InSensitive 'is' in given string are,"<<std::endl;

	// Find All case insensitive occurrences of the 'is' in the vector 'vec'
	findAllOccurances(vec, data , "iS", &findCaseInsensitive);
	for(size_t pos : vec)
		std::cout<<pos<<std::endl;

	vec.clear();

	std::cout<<"All Index Position of Case Sensitive 'is' in given string are,"<<std::endl;

	// Get All Case Sensitive occurrences of the 'is' in the vector 'vec'
	findAllOccurances(vec, data , "iS", [&](std::string data, std::string toSearch, size_t pos){
		return data.find(toSearch, pos);
	});
	for(size_t pos : vec)
		std::cout<<pos<<std::endl;


	return 0;
}

Output

All Index Position of Case InSensitive 'is' in given string are,
5
8
28
31
All Index Position of Case Sensitive 'iS' in given string are,
28