Выбрать главу

else {

ploc = ( *_word_map )[ query ];

pq = new NameQuery( query, *ploc );

}

if ( _current_op.size() = _paren )

_query_stack.push( pq );

else {

Query *pop = _current_op.top();

_current_op.pop();

pop-add_op( pq );

_query_stack.push( pop );

}

}

Упражнение 17.21

Напишите деструктор, копирующий конструктор и копирующий оператор присваивания для класса UserQuery.

Упражнение 17.22

Напишите функции print() для класса UserQuery. Обоснуйте свой выбор того, что она выводит.

17.8. Соберем все вместе

Функция main() для нашего приложения текстового поиска выглядит следующим образом:

#include "TextQuery.h"

int main()

{

TextQuery tq;

tq.build_up_text();

tq.query_text();

}

Функция-член build_text_map() - это не что иное, как переименованная функция doit() из раздела 6.14:

inline void

TextQuery::

build_text_map()

{

retrieve_text();

separate_words();

filter_text();

suffix_text();

strip_caps();

build_word_map();

}

Функция-член query_text() заменяет одноименную функцию из раздела 6.14. В первоначальной реализации в ее обязанности входили прием запроса от пользователя и вывод ответа. Мы решили сохранить за query_text() эти задачи, но реализовать ее по-другому:

void

TextQuery::query_text()

{

/* локальные объекты:

*

* text: содержит все слова запроса

* query_text: вектор для хранения пользовательского запроса

* caps: фильтр для поддержки преобразования

* прописных букв в строчные

*

* user_query: объект UserQuery, в котором инкапсулировано

* собственно вычисление ответа на запрос

*/

string text;

string caps( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" );

vectorstring, allocator query_text;

UserQuery user_query;

// инициализировать статические члены UserQuery

NotQuery::all_locs( text_locations-second );

AndQuery::max_col( &line_cnt );

UserQuery::word_map( word_map );

do {

// удалить предыдущий запрос, если он был

query_text.clear();

cout "Введите запрос. Пожалуйста, разделяйте все его "

"элементы пробелами.\n"

"Запрос (или весь сеанс) завершается точкой ( . ).\n\n"

"== ";

/*

* прочитать запрос из стандартного ввода,

* преобразовать все заглавные буквы, после чего

* упаковать его в query_text ...

*

* примечание: здесь производятся все действия по

* обработке запроса, связанные собственно с текстом ...

*/

while( cin text )

{

if ( text == "." )

break;

string::size_type pos = 0;

while (( pos = text.find_first_of( caps, pos ))

!= string::npos )

text[pos] = tolower( text[pos] );

query_text.push_back( text );

}

// теперь у нас есть внутреннее представление запроса

// обработаем его ...

if ( ! query_text.empty() )

{

// передать запрос объекту UserQuery

user_query.query( &query_text );

// вычислить ответ на запрос

// вернуть иерархию Query*

// подробности см. в разделе 17.7

// query - это член класса TextQuery типа Query*

query = user_query.eval_query();

// вычислить иерархию Query,

// реализация описана в разделе 17.7

query-eval();

// вывести ответ с помощью

// функции-члена класса TextQuery

display_solution();

// вывести на терминал пользователя дополнительную

// пустую строку

cout endl;

}

}

while ( ! query_text.empty() );

cout "До свидания!\n";

}

Тестируя программу, мы применили ее к нескольким текстам. Первым стал короткий рассказ Германа Мелвилла “Bartleby”. Здесь иллюстрируется составной запрос AndQuery, для которого подходящие слова расположены в соседних строках. (Отметим, что слова, заключенные между символами косой черты, предполагаются набранными курсивом.)

Введите запрос. Пожалуйста, разделяйте все его элементы пробелами.

Запрос (или весь сеанс) завершается точкой ( . ).

== John && Jacob && Astor

john ( 3 ) lines match

jacob ( 3 ) lines match

john && jacob ( 3 ) lines match

astor ( 3 ) lines match

john && jacob && astor ( 5 ) lines match

Requested query: john && jacob && astor

( 34 ) All who know me consider me an eminently /safe/ man. The late