Затем поток istringstream (см. раздел 8.3) используется для обработки каждого слова только что прочитанной строки. Внутренний цикл while использует оператор ввода класса istringstream для чтения каждого слова текущей строки в строку word. В цикле while используется оператор индексирования карты для доступа к связанному со словом указателю shared_ptr и связи ссылки lines с этим указателем. Обратите внимание, что lines — это ссылка, поэтому внесенные в нее изменения будут сделаны с элементом карты wm.

Если слова еще нет в карте, оператор индексирования добавит строку word в карту wm (см. раздел 11.3.4). Ассоциируемый со строкой word элемент инициализирован значением по умолчанию. Это значит, что ссылка lines будет нулевой, если оператор индексирования добавит строку word в карту wm. Если ссылка lines будет нулевой, резервируем новый набор и вызываем функцию reset() для обновлении указателя shared_ptr, на который ссылается ссылка lines, чтобы он указывал на этот только что созданный набор.

Независимо от того, был ли создан новый набор, происходит вызов функции insert(), добавляющей текущий номер строки. Поскольку lines — это ссылка, вызов функции insert() добавляет элемент в набор карты wm. Если данное слово встречается несколько раз в той же строке, вызов функции insert() не делает ничего.

Класс QueryResult

Класс QueryResult обладает тремя переменными-членами: строка, представляющая слово, указатель shared_ptr на вектор, содержащий входной файл; и указатель shared_ptr на набор номеров строк, в которых присутствует это слово. Его единственная функция-член — конструктор, инициализирующий эти три члена:

class QueryResult {

 friend std::ostream& print(std::ostream&, const QueryResult&);

public:

 QueryResult(std::string s,

             std::shared_ptr> p,

             std::shared_ptr> f):

  sought(s), lines(p), file(f) { }

private:

 std::string sought; // слово, представляющее запрос

 std::shared_ptr> lines;       // номера строк

 std::shared_ptr> file; // входной файл

};

Единственная задача конструктора — сохранить свои аргументы в соответствующих переменных-членах, что он и делает в списке инициализации конструктора (см. раздел 7.1.4).

Функция query()

Функция query() получает строку, которую она использует для поиска соответствующего набора номеров строк в карте. Если строка найдена, функция query() создает объект класса QueryResult из заданной строки, переменной-члена file класса TextQuery и набора, извлеченного из карты wm.

Единственный вопрос: что следует возвратить, если заданная строка не найдена? В данном случае никакого набора возвращено не будет. Решим эту проблему, определив локальный статический объект, являющийся указателем shared_ptr на пустой набор номеров строк. Когда слово не найдено, возвратим копию этого указателя shared_ptr:

QueryResult

TextQuery::query(const string &sought) const {

 // возвратить указатель на этот набор, если искомое слово не найдено

 static shared_ptr> nodata(new set);

 // использовать find() но не индексировать, чтобы избежать

 // добавления слова в карту wm!

 auto loc = wm.find(sought);

 if (loc == wm.end())

  return QueryResult(sought, nodata, file); // не найдено

 else

  return QueryResult(sought, loc->second, file);

}

Вывод результатов

Функция print() выводит заданный объект класса QueryResult в заданный поток:

ostream &print(ostream &os, const QueryResult &qr) {

 // если слово найдено, вывести количество и все вхождения

 os << qr.sought << " occurs " << qr.lines->size() << " "

    << make_plural(qr.lines->size(), "time", "s") << endl;

 // вывести каждую строку, в которой присутствует слово

 for (auto num : *qr.lines) // для каждого элемента в наборе

  // не путать пользователя с номерами строк, начинающимися с 0

  os << "\t (line " << num + 1 << ") "

Перейти на страницу:

Похожие книги