11. Теперь воспользуемся вновь добавленной функцией. Сначала укажем std::cin
не пропускать пробельные символы, поскольку нам нужны предложения с пробелами как единое целое. Чтобы считать весь файл, инициализируем std::string
на основе итераторов потока ввода, которые инкапсулируют std::cin
:
int main()
{
cin.unsetf(ios::skipws);
string content {istream_iterator
12. Поскольку нужен полученный контейнер multimap
лишь для того, чтобы вывести на экран результат, помещаем вызов функции get_sentence_stats
непосредственно в цикл и передаем ему нашу строку. В теле цикла выведем элементы построчно:
for (const auto & [word_count, sentence]
: get_sentence_stats(content)) {
cout << word_count << " words: " << sentence << ".\n";
}
}
13. После компиляции кода мы можем дать приложению команду использовать содержимое любого текстового файла. Текст-пример Lorem Ipsum
даст следующий результат. Вывод на экран довольно велик для длинных текстов с большим количеством предложений: сначала выводятся самые короткие предложения, а затем — самые длинные. В результате мы сразу видим самые длинные предложения, поскольку обычно по умолчанию на экране отображается нижняя часть вывода:
$ cat lorem_ipsum.txt | ./sentence_length
[5]
...
10 words: Nam quam nunc, blandit vel, luctus pulvinar,
hendrerit id, lorem.
10 words: Sed consequat, leo eget bibendum sodales,
augue velit cursus nunc,.
12 words: Cum sociis natoque penatibus et magnis dis
parturient montes, nascetur ridiculus mus.
17 words: Maecenas tempus, tellus eget condimentum rhoncus,
sem quam semper libero, sit amet adipiscing sem neque sed ipsum.
Как это работает
Весь этот пример посвящен разбиению большой строки на предложения, после чего мы определяем их длину и помещаем в контейнер multimap
в упорядоченном виде. Поскольку контейнер std::multimap
сам по себе прост в использовании, сложной частью программы является цикл, который проходит по всем предложениям:
const auto end_it (end(content));
auto it1 (begin(content)); // (1) Начало строки
auto it2 (find(it1, end_it, '.')); // (1) Первая точка '.'
while (it1 != end_it && std::distance(it1, it2) > 0) {
string sentence {it1, it2};
// Что-то делаем со строкой предложения...
it1 = std::next(it2, 1); // Один символ справа от текущей точки '.'
it2 = find(it1, end_it, '.'); // Следующая точка или конец строки
}
Взглянем на код, имея при этом в виду следующий рисунок, на котором приведены три предложения (рис. 2.5).
Итераторы it1
и it2
всегда перемещаются вперед по строке вместе. Таким образом, они всегда указывают на начало и конец std::find
заметно облегчает нам жизнь, поскольку работает по принципу
После извлечения строки с предложением определим, сколько слов в ней содержится, а затем вставим ее в контейнер multimap
. Мы используем std::map
, так как предложений одинаковой длины может быть довольно много. Но это не проблема, поскольку мы задействуем контейнер std::multimap
, который легко справляется с совпадающими ключами. Данный контейнер хранит ключи
Дополнительная информация