// фрагмент программы
// pos: позиция на 1 большая конца слова
// prev_pos: позиция начала слова
string::size_type pos = 0, prev_pos = 0;
while (( pos = textline.find_first_of( ' ', pos ))
!= string::npos )
{
// ...
// запомнить позицию начала слова
prev_pos = ++pos;
}
На каждой итерации prev_pos указывает позицию начала слова, а pos – позицию следующего символа после его конца. Соответственно, длина слова равна:
pos - prev_pos; // длина слова
После того как мы выделили слово, необходимо поместить его в строковый вектор. Это можно сделать, копируя в цикле символы из textline с позиции prev_pos до pos -1. Функция substr() сделает это за нас:
// фрагмент программы
vectorstring words;
while (( pos = textline.find_first_of( ' ', pos ))
!= string::npos )
{
words.push_back( textline.substr(
prev_pos, pos-prev_pos));
prev_pos = ++pos;
}
Функция substr() возвращает копию подстроки. Первый ее аргумент обозначает первую позицию, второй – длину подстроки. (Второй аргумент можно опустить, тогда подстрока включит в себя остаток исходной строки, начиная с указанной позиции.)
В нашей реализации допущена ошибка: последнее слово не будет помещено в контейнер. Почему? Возьмем строку:
seaspawn and seawrack
После каждого из первых двух слов поставлен пробел. Два вызова функции find_first_of() вернут позиции этих пробелов. Третий же вызов вернет string::npos, и цикл закончится. Таким образом, последнее слово останется необработанным.
Вот полный текст функции, названной нами separate_words(). Помимо сохранения слов в векторе строк, она вычисляет координаты каждого слова – номер строки и колонки (нам эта информация потребуется впоследствии).
typedef pairshort,short location;
typedef vectorlocation loc;
typedef vectorstring text;
typedef pairtext* ,loc* text_loc;
text_loc*
separate_words( const vectorstring *text_file )
{
// words: содержит набор слов
// locations: содержит информацию о строке и позиции
// каждого слова
vectorstring *words = new vectorstring;
vectorlocation * locations = new vectorlocation;
short line_pos = 0; // текущий номер строки
// iterate through each line of text
for ( ; line_pos text_file-size(); ++line_pos )
// textline: обрабатываемая строка
// word_pos: позиция в строке
short word_pos = 0;
string textline = (*text_file) [ line_pos ];
string::size_type pos = 0, prev_pos = 0;
while (( pos = textline.find_first_of( ' ', pos ))
!= string::npos )
{
// сохраним слово
words-push_back(
textline.substr( prev_pos, pos - prev_pos ));
// сохраним информацию о его строке и позиции
locations-push_back(
make_pair( line_pos, word_pos ));
// сместим позицию для следующей итерации
++word_pos; prev_pos = ++pos;
}
// обработаем последнее слово
words-push_back(
textline.substr( prev_pos, pos - prev_pos ));
locations-push_back(
make_pair( line_pos, word_pos ));
}
return new text_loc( words, locations );
}
Теперь функция main()выглядит следующим образом:
int main()
{
vectorstring *text_file = retrieve_text();
text_loc *text_locations = separate_words( text_file );
// ...
}
Вот часть распечатки, выданной тестовой версией separate_words():
textline: Alice Emma has long flowing red hair. Her Daddy
says
eol: 52 pos: 5 line: 0 word: 0 substring: Alice