In this section, we will implement the remove_multi_whitespace algorithm and check out how it works:
- As always, we do some includes first and then declare that we use the std namespace by default:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
- We implement a new STL-style algorithm called remove_multi_whitespace. This algorithm removes clustered occurrences of whitespace, but no single spaces. This means that a string line "a b" stays unchanged, but a string like
"a b" is shrunk to "a b". In order to accomplish this, we use std::unique with a custom binary predicate function. The std::unqiue walks through an iterable range and always looks at consecutive pairs of payload items. Then it asks the predicate functions whether two items are equal. If they are, then std::unique removes one of them. Afterward, the range does not contain subranges with equal items sitting next to each other. Predicate functions that are usually applied in this context tell whether two items are equal. What we do, is give std::unique a predicate, which tells if there are two consecutive spaces in order to get those removed. Just like std::unique, we accept a pair of begin/end iterators, and then return an iterator pointing to the new end of the range:
template <typename It>
It remove_multi_whitespace(It it, It end_it)
{
return unique(it, end_it, [](const auto &a, const auto &b) {
return isspace(a) && isspace(b);
});
}
- That is already it. Let's construct a string that contains some unnecessary whitespace:
int main()
{
string s {"fooo bar t baz"};
cout << s << 'n';
- Now, we use the erase-remove idiom on the string in order to get rid of the excess whitespace characters:
s.erase(remove_multi_whitespace(begin(s), end(s)), end(s));
cout << s << 'n';
}
- Compiling and running the program yields the following output:
$ ./remove_consecutive_whitespace
fooo bar baz
fooo bar baz