4.18. Подсчет вхождений каждого слова в текстовом файле
4.18. Подсчет вхождений каждого слова в текстовом файле
Проблема
Требуется подсчитать количество вхождений в текстовом файле каждого слова.
Решение
Для чтения из текстового файла непрерывных фрагментов текста используйте operator>>, определенный в <string>, а для сохранения каждого слова и его частоты в файле используйте map, определенный в <map>. Пример 4.27 демонстрирует, как это делается.
Пример 4.27. Подсчет частоты слов
1 #include <iostream>
2 #include <fstream>
3 #include <map>
4 #include <string>
5
6 typedef std::map<std::string, int> StrIntMap;
7
8 void countWords(std::istream& in, StrIntMap& words) {
9
10 std::string s;
11
12 while (in >> s) {
13 ++words[s];
14 }
15 }
16
17 int main(int argc, char** argv) {
18
19 if (argc < 2)
20 return(EXIT_FAILURE);
21
22 std::ifstream in(argv[1]);
23
24 if (!in)
25 exit(EXIT_FAILURE);
26
27 StrIntMap w;
28 countWords(in, w);
29
30 for (StrIntMap::iterator p = w.begin();
31 p != w.end(); ++p) {
32 std::cout << p->first << " присутствует "
33 << p->second << " раз. ";
34 }
35 }
Обсуждение
Пример 4.27 кажется вполне простым, но в нем делается больше, чем кажется. Большая часть тонкостей связана с map, так что вначале давайте обсудим его.
Если вы не знакомы с map, то вам стоит узнать про него, map — это шаблон класса контейнера, который является частью STL. Он хранит пары ключ-значение в порядке, определяемом std::less или вашей собственной функцией сравнения. Типы ключей и значений, которые можно хранить в нем, зависят только от вашего воображения. В этом примере мы просто сохраняем string и int.
В строке 6 я для упрощения читаемости кода использовал typedef.
typedef map<string, int> StrIntMap;
Таким образом, StrIntMap — это map, который хранит пары string/int. Каждая string — это уникальное слово именно по этой причине я использую ее как ключ, — которое было прочитано из входного потока, а связанное с ней int — это число раз, которое это слово встретилось. Все, что осталось, — это прочитать все слова по одному, добавить их в map, если их там еще нет, и увеличить значение счетчика, если они там уже есть.
Это делает countWords. Основная логика кратка.
while (in >> s) {
++words[s];
}
operator>> читает из левого операнда (istream) непрерывные отрезки, не содержащие пробелов, и помещает их в правый операнд (string). После прочтения слова все, что требуется сделать, — это обновить статистику в map, и это делается в следующей строке.
++words[s];
map определяет operator[], позволяющий получить значение данного ключа (на самом деле он возвращает ссылку на само значение), так что для его инкремента просто инкрементируется значение, индексируемое с помощью заданного ключа. Но здесь могут возникнуть небольшие осложнения. Что, если ключа в map еще нет? Разве мы не попытаемся увеличить несуществующий элемент, и не обрушится ли программа, как в случае с обычным массивом? Нет, map определяет operator[] не так, как другие контейнеры STL или обычные массивы.
В map operator[] делает две вещи: если ключ еще не существует, он создает значение, используя конструктор типа значения по умолчанию, и добавляет в map эту новую пару ключ/значение, а если ключ уже существует, то никаких изменений не вносится. В обоих случаях возвращается ссылка на значение, определяемое ключом, даже если это значение было только что создано конструктором по умолчанию. Это удобная возможность (если вы знаете о ее существовании), так как он устраняет необходимость проверки в клиентском коде существования ключа перед его добавлением.
Теперь посмотрите на строки 32 и 33. Итератор указывает на члены, которые называются first и second — что это такое? map обманывает вас, используя для хранения пар имя/значение другой шаблон класса: шаблон класса pair, определенный в <utility> (уже включенный в <map>). При переборе элементов, хранящихся в map, вы получите ссылки на объекты pair. Работа с pair проста. Первый элемент пары хранится в элементе first, а второй хранится, естественно, в second.
В примере 4.27 я для чтения из входного потока непрерывных фрагментов текста использую operator>>, что отличается от некоторых других примеров. Я делаю это для демонстрации того, как это делается, но вам почти наверняка потребуется изменить его поведение в зависимости от определения «слова» текстового файла. Например, рассмотрим фрагмент вывода, генерируемого примером 4.27.
with присутствует 5 раз.
work присутствует 3 раз.
workers присутствует 3 раз.
workers, присутствует 1 раз.
years присутствует 2 раз.
years, присутствует 1 раз.
Обратите внимание, что точки в конце слов рассматриваются как части слов. Скорее всего, вам потребуется с помощью функций проверки символов из <cctype> и <cwctype> изменить определение слова так, чтобы оно означало только буквенно-цифровые символы, как это сделано в рецепте 4.17.
Смотри также
Рецепт 4.17 и табл. 4.3.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Место не для каждого
Место не для каждого Позиция вверху SERP гарантирует площадке поток целевых посетителей, но не каждому проекту имеет смысл тратить бюджет на продвижение с целью занять первые места в поисковой выдаче. Каким же сайтам нет резона метить в топ и почему?1. Только что «сошедший
14.4.1 Использование команд в текстовом диалоге
14.4.1 Использование команд в текстовом диалоге Многие пользователи предпочитают графический интерфейс, доступный на настольных системах, но текстовый интерфейс позволяет лучше понять внутренние процессы протокола FTP.Нижеприведенный текстовый диалог начинается с
2.28. Подсчет числа символов в строке
2.28. Подсчет числа символов в строке Метод count подсчитывает число вхождений в строку символов из заданного набора:s1 = "abracadabra"a = s1.count("с") # 1b = s1.count("bdr") # 5Строковый параметр ведет себя как простое регулярное выражение. Если он начинается с символа ^, то берется дополнение к
4.21. Замена в текстовом файле последовательностей пробелов на один пробел
4.21. Замена в текстовом файле последовательностей пробелов на один пробел ПроблемаИмеется текстовый файл с последовательностями пробелов различной длины и требуется заменить каждое вхождение такой последовательности на единственный пробел.РешениеДля чтения
11.1. Подсчет количества элементов в контейнере
11.1. Подсчет количества элементов в контейнере ПроблемаТребуется найти количество элементов в контейнере.РешениеПодсчитать количество элементов в контейнере можно при помощи функции-члена size или функции distance, определенной в заголовочном файле <algorithm>, как это
Подсчет ссылок
Подсчет ссылок При описании STL практически невозможно обойти стороной подсчет ссылок. Как будет показано в советах 7 и 33, любая архитектура, основанная на контейнерах указателей, практически всегда основана на подсчете ссылок. Кроме того, подсчет ссылок используется во
Подсчет (Count)
Подсчет (Count) template ‹class InputIterator, class T, class Size›void count(InputIterator first, InputIterator last, const T& value, Size& n);template ‹class InputIterator, class Predicate, class Size›void count_if(InputIterator first, InputIterator last, Predicate pred, Size& n);count добавляет к n число итераторов i в диапазоне [first, last), для которых соблюдаются следующие
Количество строк в текстовом поле
Количество строк в текстовом поле Если у текстового поля свойство Multiline имеет значение True, то свойство Lines возвращает массив строк в текстовом поле. Но у данного свойства есть два недостатка. Во-первых, свойство Lines не поддерживается библиотекой .NET Compact Framework, а во-вторых,
21.4.5. Команда wc — подсчет слов в файле
21.4.5. Команда wc — подсчет слов в файле Команда wc используется:? для подсчета слов в текстовом файле: wc /var/log/messages ? для подсчета количества строк (если задан параметр -1): wc — l /var/log/messages ? для подсчета количества символов (параметр — c): wc — c
18.5.9. Подсчет с помощью циклов
18.5.9. Подсчет с помощью циклов При обсуждении команды expr отмечалось, что эта команда применяется, если в циклы необходимо ввести счетчики. Ниже рассматривается пример, в котором цикл for обрабатывает файлы, а вывод и подсчет количества файлов осуществляется с помощью
Подсчет ссылок
Подсчет ссылок Простая идея лежит в основе первого метода управления памятью - подсчета ссылок. Каждый объект хранит текущее число сделанных на него ссылок. Когда оно становится равным нулю, объект можно утилизировать.Это решение не сложно для реализации на уровне языка.
Слова, слова, слова… Автор: Евгений Козловский.
Слова, слова, слова… Автор: Евгений Козловский. © 2004, Издательский дом | http://www.computerra.ru/Журнал «Домашний компьютер» | http://dk.compulenta.ru/Этот материал Вы всегда сможете найти по его постоянному адресу: /2006/120/276445/Интересно, сколько двенадцатизначных чисел вы способны оперативно