#include string
#include iostream
int main() {
string numerics( "0123456789" );
string name( "r2d2" );
string::size_type pos = 0;
// где-то здесь ошибка!
while (( pos = name.find_first_of( numerics, pos ))
!= string::npos )
cout "найдена цифра в позиции: "
pos "\tэлемент равен "
name[pos] endl;
}
В начале цикла pos равно 0, поэтому поиск идет с начала строки. Первое вхождение обнаружено в позиции 1. Поскольку найденное значение не совпадает с string::npos, выполнение цикла продолжается. Для второго вызова find_first_of()значение pos равно 1. Поиск начнется с 1-й позиции. Вот ошибка! Функция find_first_of() снова найдет цифру в первой позиции, и снова, и снова... Получился бесконечный цикл. Нам необходимо увеличивать pos на 1 в конце каждой итерации:
// исправленная версия цикла
while (( pos = name.find_first_of( numerics, pos ))
!= string::npos )
{
cout "найдена цифра в позиции: "
pos "\tэлемент равен "
name[pos] endl;
// сдвинуться на 1 символ
++pos;
}
Чтобы найти все пустые символы (к которым, помимо пробела, относятся символы табуляции и перевода строки), нужно заменить строку numerics в этом примере строкой, содержащей все эти символы. Если же мы уверены, что используется только символ пробела и никаких других, то можем явно задать его в качестве параметра функции:
// фрагмент программы
while (( pos = textline.find_first_of( ' ', pos ))
!= string::npos )
// ...
Чтобы узнать длину слова, введем еще одну переменную:
// фрагмент программы
// 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 ));
// сместим позицию для следующей итерации