Посмотрим, как можно построить отображение для хранения нашего текста. Функция separate_words(), описанная в разделе 6.8, создает два объекта: вектор строк, хранящий все слова текста, и вектор позиций, хранящий пары (номер строки, номер колонки) для каждого слова. Таким образом, первый объект дает нам множество значений ключей нашего отображения, а второй – множество ассоциированных с ними значений.
separate_words() возвращает эти два вектора как объект типа pair, содержащий указатели на них. Сделаем эту пару аргументом функции build_word_map(), в результате которой будет получено соответствие между словами и позициями:
// typedef для удобства чтения
typedef pair short,short location;
typedef vector location loc;
typedef vector string text;
typedef pair text*,loc* text_loc;
extern map string, loc* *
build_word_map( const text_loc *text_locations );
Сначала выделим память для пустого объекта map и получим из аргумента-пары указатели на векторы:
mapstring,loc* *word_map = new map string, loc* ;
vectorstring *text_words = text_locations-first;
vectorlocation *text_locs = text_locations-second;
Теперь нам надо синхронно обойти оба вектора, учитывая два случая:
* слово встретилось впервые. Нужно поместить в map новую пару ключ/значение;
* слово встречается повторно. Нам нужно обновить вектор позиций, добавив дополнительную пару (номер строки, номер колонки).
Вот текст функции:
register int elem_cnt = text_words-size();
for ( int ix=0; ix elem_cnt; ++ix )
{
string textword = ( *text_words )[ ix ];
// игнорируем слова короче трех букв
// или присутствующие в списке стоп-слов
if ( textword.size() 3 ||
exclusion_set.count( textword ))
continue;
// определяем, занесено ли слово в отображение
// если count() возвращает 0 - нет: добавим его
if ( ! word_map-count((*text_words)[-ix] ))
{
loc *ploc = new vectorlocation;
ploc-push_back( (*text_locs) [ix] );
word_map-insert(value_type((*text_words)[ix],ploc));
}
else
// добавим дополнительные координаты
(*word_map)[(*text_words)[ix]]-
push_back((*text_locs)[ix]);
}
Синтаксически сложное выражение
(*word_map)[(*text_words)[ix]]-
push_back((*text_locs)[ix]);
будет проще понять, если мы разложим его на составляющие:
// возьмем слово, которое надо обновить
string word = (*text_words) [ix];
// возьмем значение из вектора позиций
vectorlocation *ploc = (*word_map) [ word ];
// возьмем позицию - пару координат
loc = (*text_locs)[ix];
// вставим новую позицию
ploc-push_back(loc);
Выражение все еще остается сложным, так как наши векторы представлены указателями. Поэтому вместо употребления оператора взятия индекса:
string word = text_words[ix]; // ошибка
мы вынуждены сначала разыменовать указатель на вектор:
string word = (*text_words) [ix]; // правильно
В конце концов build_word_map() возвращает построенное отображение:
return word_map;
Вот как выглядит вызов этой функции из main():
int main()
{
// считываем файл и выделяем слова
vectorstring, allocator *text_file = retrieve_text();
text_loc *text_locations = separate_words( text_file );
// обработаем слова
// ...
// построим отображение слов на векторы позиций
mapstring,lос*,lessstring,allocator
*text_map = build_word_map( text_locatons );
// ...
}
6.12.2. Поиск и извлечение элемента отображения