Мы несколько раз вызвали алгоритм gather
begin()
и end()
этих диапазонов. Эти случаи интересны тем, что всегда приводят один из вызовов std::stable_partition
к работе с пустым диапазоном данных, а это влечет Для последнего вызова gather
(begin, end, middle)
и не получили результат. Почему? На первый взгляд это похоже на баг, но на самом деле все не так.Представьте, что у нас есть диапазон символов "aabb"
is_character_a
, которая возвращает значение true
для элементов 'a'
, — если мы вызовем ее с третьим итератором, указывающим на середину диапазона символов, то увидим такой же stable_ partition
будет работать с диапазоном "aa"
, а второй — с диапазоном "bb"
. Эта последовательность вызовов не даст получить результат "baab"
, на который мы наивно надеялись. std::rotate(begin, begin + 1, end);
Модификация gather_sort
gather
. Единственное отличие заключается в следующем: она принимает не унарную функцию-предикат, а бинарную функцию сравнения, как и std::sort
. И вместо того, чтобы дважды вызывать std::stable_partition
, она дважды вызывает std::stable_sort
.Функцию инвертирования сравнения нельзя реализовать с помощью not_fn
gather
, поскольку not_fn
не работает с бинарными функциями. Удаляем лишние пробелы между словами
Зачастую полученные от пользователей строки могут иметь самое разное форматирование, и их нужно отредактировать. Например, нужно удалить повторяющиеся пробелы.
В этом разделе мы реализуем быстрый алгоритм удаления таких пробелов, который сохраняет одиночные пробелы. Мы назовем данный алгоритм remove_multi_whitespace
Как это делается
В этом примере мы реализуем алгоритм remove_multi_whitespace
1. Как и всегда, сначала приведем несколько директив include
#include
#include
#include
using namespace std;
2. Реализуем новый алгоритм в стиле STL, который называется remove_multi_ whitespace
"a b"
останется неизменной, но строка "a b"
будет сокращена до "a b"
. Для этого мы применим функцию std::unique
с пользовательской бинарной функцией-предикатом. Функция std::unqiue
итерирует по диапазону данных и всегда ищет соседствующие элементы. Затем с помощью функции-предиката она определяет, равны ли искомые элементы. Если да, то удаляет один из них. После вызова этой функции диапазон данных не будет содержать поддиапазонов, в которых одинаковые элементы стоят друг рядом с другом. Функции-предикаты, обычно применяемые в этом контексте, говорят, равны ли два элемента. Мы передадим функции std::unique
предикат, который укажет, стоят ли рядом два std::unique
, мы принимаем начальный и конечный итераторы, а затем возвращаем итератор, указывающий на новый конец диапазона данных:template
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);
});
}
3. На этом все. Создадим строку, которая содержит лишние пробелы.
int main()
{
string s {"fooo bar \t baz"}; cout << s << '\n';
4. Теперь воспользуемся
s.erase(remove_multi_whitespace(begin(s), end(s)), end(s));
cout << s << '\n';
}
5. Компиляция и запуск программы дадут следующий результат:
$ ./remove_consecutive_whitespace
fooo bar baz
fooo bar baz
Как это работает