4.11. Removing a Substring from a String

Problem

You want to remove a substring from a string.

Solution

Use the find, erase, and length member functions of basic_string:

std::string t = "Banana Republic";
std::string s = "nana";

std::string::size_type i = t.find(s);

if (i != std::string::npos)
   t.erase(i, s.length());

This will erase s.length() elements starting at the index where find found the first occurrence of the substring.

Discussion

There are lots of variations on the theme of finding a substring and removing it. For example, you may want to remove all instances of a substring instead of just one. Or just the last one. Or the seventh one. Each time the steps are the same: find the index of the beginning of the pattern you want to remove, then call erase on that index for the next n characters, where n is the length of the pattern string. See Recipe 4.9 for the different member functions for finding things in strings.

Chances are you also want to make your substring-removal function generic, so you can use it on strings of any kind of character. Example 4-19 offers a generic version that removes all instances of the pattern from a string.

Example 4-19. Remove all substrings from a string (generic version)

#include <string>
#include <iostream>

using namespace std;

template<typename T>
void removeSubstrs(basic_string<T>& s,
                   const basic_string<T>& p) {
   basic_string<T>::size_type n = p.length();

   for (basic_string<T>::size_type i = s.find(p);
        i != basic_string<T>::npos;
        i = s.find(p))
      s.erase(i, n);
}

int main() {
   string s = "One fish, two fish, red fish, blue fish";
   string p = "fish";

   removeSubstrs(s, p);

   cout << s << '\n';
}

The basic_string member function erase is what does the important work here. In <string>, it is overloaded three times. The version I used in Example 4-19 accepts the index to begin erasing at and the number of characters to erase. Another version accepts starting and ending iterator arguments, and there is a version that takes a single iterator and erases the element at that location. To ensure optimal performance, prefer the first two when you plan to delete multiple contiguous elements instead of repeatedly calling s.erase(iter) for each element you want to erase. In other words, use member functions that operate on ranges instead of single elements—especially for those member functions that modify the contents of the string (or sequence). By doing so, you will avoid the extra function calls to erase for each element in the sequence, and you will permit the string implementation to more intelligently manage its data.

Get C++ Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.