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