С.Б. Липпман, Ж. Лажойе - Язык программирования С++ Вводный курс (1114944), страница 46
Текст из файла (страница 46)
Her Daddysayseol:eol:eol:eol:eol:eol:eol:eol:eol:last52 pos:52 pos:52 pos:52 pos:52 pos:52 pos:52 pos:52 pos:52 pos:word on5 line: 0 word: 0 substring: Alice10 line: 0 word: 1 substring: Emma14 line: 0 word: 2 substring: has19 line: 0 word: 3 substring: long27 line: 0 word: 4 substring: flowing31 line: 0 word: 5 substring: red37 line: 0 word: 6 substring: hair.41 line: 0 word: 7 substring: Her47 line: 0 word: 8 substring: Daddyline substring: says...textline: magical but untamed. "Daddy, shush, there is nosuch thing,"eol:eol:eol:eol:eol:eol:eol:eol:eol:last60 pos:60 pos:60 pos:60 pos:60 pos:60 pos:60 pos:60 pos:60 pos:word on7 line: 3 word: 0 substring: magical11 line: 3 word: 1 substring: but20 line: 3 word: 2 substring: untamed28 line: 3 word: 3 substring: "Daddy,35 line: 3 word: 4 substring: shush,41 line: 3 word: 5 substring: there44 line: 3 word: 6 substring: is47 line: 3 word: 7 substring: no52 line: 3 word: 8 substring: suchline substring: thing,":...textline: Shy1y, she asks, "I mean, Daddy: is there?"eol:eol:eol:eol:eol:eol:eol:last43 pos:43 pos:43 pos:43 pos:43 pos:43 pos:43 pos:word on6 line: 5 word: 0 substring: Shyly,10 line: 5 word: 1 substring: she16 line: 5 word: 2 substring: asks,19 line: 5 word: 3 substring: "I25 line: 5 word: 4 substring: mean,32 line: 5 word: 5 substring: Daddy,35 line: 5 word: 6 substring: isline substring: there?":Прежде чем продолжить реализацию поисковой системы, вкратце рассмотримоставшиеся функции-члены класса string, предназначенные для поиска.
Функцияstring river( "Mississippi" );string::size_type first_pos = river.find( "is" );rfind() ищет последнее, т.е. самое правое, вхождение указанной подстроки:string::size_type 1ast_pos = river.rfind( "is" );find() вернет 1, указывая позицию первого вхождения подстроки "is", а rfind() – 4(позиция последнего вхождения "is").find_first_not_of() ищет первый символ, не содержащийся в строке, переданной какпараметр. Например, чтобы найти первый символ, не являющийся цифрой, можнонаписать:274С++ для начинающих275string elems( "0123456789" );string dept_code( "03714p3" );// возвращается позиция символа 'p'string::size_type pos = dept_code.find_first_not_of(elems) ;find_last_of() ищет последнее вхождение одного из указанных символов.find_last_not_of() – последний символ, не совпадающий ни с одним из заданных.
Всеэти функции имеют второй необязательный параметр – позицию в исходной строке, скоторой начинается поиск.Упражнение 6.13Напишите программу, которая ищет в строке"ab2c3d7R4E6"цифры, а затем буквы,find_first_not_of().используясначалаfind_first_of(),апотомУпражнение 6.14Напишите программу, которая подсчитывает все слова и определяет самое длинное иstring linel = "We were her pride of 10 she named us --";string line2 = "Benjamin, Phoenix, the Prodigal"string line3 = "and perspicacious pacific Suzanne";самое короткое из них в строке sentence:string sentence = linel + line2 + line3;Если несколько слов имеют длину, равную максимальной или минимальной, учтите ихвсе.6.9.
Обрабатываем знаки препинанияПосле того как мы разбили каждую строку на слова, необходимо избавиться от знаковпрепинания. Пока из строкиmagical but untamed. "Daddy, shush, there is no such thing,"у нас получился такой набор слов:magicalbutuntamed."Daddy,shush,thereisnoС++ для начинающихsuchthing,"Как нам теперь удалить ненужные знаки препинания? Для начала определим строку,содержащую все символы, которые мы хотим удалить:string filt_elems( "\",.;:!?)(\\/" );(Обратная косая черта указывает на то, что следующий за ней символ должен в данномконтексте восприниматься буквально, а не как специальная величина. Так, \" обозначаетсимвол двойной кавычки, а не конец строки, а \\ – символ обратной косой черты.)Теперь можно применить функцию-член find_first_of() для поиска всех вхожденийwhile (( pos = word.find_first_of( filt_elems, pos ))нежелательных символов:!= string::npos )Найденный символ удаляется с помощью функции-члена erase():word.erase(pos,1);Первый аргумент этой функции означает позицию подстроки, а второй – ее длину.
Мыудаляем один символ, находящийся в позиции pos. Второй аргумент являетсянеобязательным; если его опустить, будут удалены все символы от pos до конца строки.Вот полный текст функции filter_text(). Она имеет два параметра: указатель наvoidfilter_text( vector<string> *words, string filter ){vector<string>::iterator iter = words->begin();vector<string>::iterator iter_end = words->end();// Если filter не задан, зададим его самиif ( ! filter.size() )filter.insert( 0, "\".," );while ( iter != iter_end ) {string::size_type pos = 0;// удалим каждый найденный элементwhile (( pos = (*iter).find_first_of( filter, pos ))!= string::npos )(*iter).erase(pos,1);iter++;}вектор строк, содержащий текст, и строку с символами, которые нужно убрать.}Почему мы не увеличиваем значение pos на каждой итерации? Что было бы, если бы мынаписали:276С++ для начинающихwhile (( pos = (*iter).find_first_of( filter, pos ))!= string::npos ){(*iter).erase(pos,1);++ pos; // неправильно...}Возьмем строкуthing,"На первой итерации pos получит значение 5 , т.е.
позиции, в которой находится запятая.После удаления запятой строка примет видthing"Теперь в 5-й позиции стоит двойная кавычка. Если мы увеличим значение pos, топропустим этот символ.string filt_elems( "\",.;:!?)(\\/" );Так мы будем вызывать функцию filter_text():filter_text( text_locations->first, filt_elems );А вот часть распечатки, сделанной тестовой версией filter_text():filter_text: untamed.found! : pos: 7.after: untamedfilter_text: "Daddy,found! : pos: 0.after: Daddy,found! : pos: 5.after: Daddyfilter_text: thing,"found! : pos: 5.after: thing"found! : pos: 5.after: thingfilter_text: "Ifound! : pos: 0.after: Ifilter_text: Daddy,found! : pos: 5.after: Daddyfilter_text: there?"found! : pos: 5.after: there"found! : pos: 5.after: there277С++ для начинающихУпражнение 6.15Напишите программу, которая удаляет все символы, кроме STL из строки:"/.+(STL).$1/"используя сначала erase(pos,count), а затем erase(iter,iter).Упражнение 6.16string sentence( "kind of" );string s1 ( "whistle" )Напишите программу, которая с помощью разных функций вставки из строкstring s2 ( "pixie" )составит предложение"A whistling-dixie kind of walk"6.10.
Приводим слова к стандартной формеОдной из проблем при разработке текстовых поисковых систем является необходимостьраспознавать слова в различных словоформах, такие, как cry, cries и cried, baby иbabies, и, что гораздо проще, написанные заглавными и строчными буквами, напримерhome и Home. Первая задача, распознавание словоформ, слишком сложна, поэтому мыприведем здесь ее заведомо неполное решение.
Сначала заменим все прописные буквыvoidstrip_caps( vector<string,allocator> *words ){vector<string,allocator>::iterator iter=words->begin() ;vector<string,allocator>::iterator iter_end=words->end() ;string caps( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" );while ( iter != iter_end ) {string::size_type pos = 0;while (( pos = (*iter).find_first_of( caps, pos ))!= string::npos )(*iter)[ pos ] = to1ower( (*iter)[pos] );++iter;}строчными:}Функцияto1ower( (*iter)[pos] );278С++ для начинающихвходит в стандартную библиотеку С. Она заменяет прописную букву соответствующей ейстрочной. Для использования tolower() необходимо включить заголовочный файл:#include <ctype.h>(В этом файле объявлены и другие функции, такие, как isalpha(), isdigit(),ispunct(), isspace(), toupper(). Полное описание этих функций см.
[PLAUGER92].Стандартная библиотека С++ включает класс ctype, который инкапсулирует всюфункциональность стандартной библиотеки Си, а также набор функций, не являющихсячленами, например toupper(), tolower() и т.д. Для их использования нужно включитьзаголовочный файл#include <locale>Однако наша реализация компилятора еще не поддерживала класс ctype, и нампришлось использовать стандартную библиотеку Си.)Проблема словоформ слишком сложна для того, чтобы пытаться решить ее в общем виде.Но даже самый примитивный вариант способен значительно улучшить работу нашейпоисковой системы.
Все, что мы сделаем в данном направлении, – удалим букву 's' наvoid suffix_text( vector<string,allocator> *words ){vector<string,allocator>::iteratoriter = words->begin(),iter_end = words->end();while ( iter != iter_end ) {// оставим слова короче трех букв как естьif ( (*iter).size() <= 3 ){ ++iter; continue; }if ( (*iter)[ (*iter).size()-1 ] == 's' )suffix_s( *iter );// здесь мы могли бы обработать суффиксы// ed, ing, 1y++iter;}концах слов:}Слова из трех и менее букв мы пропускаем. Это позволяет оставить без изменения,например, has, its, is и т.д., однако слова tv и tvs мы не сможем распознать какодинаковые.string::size_type pos() = word.size()-3;string ies( "ies" );if ( ! word.compare( pos3, 3, ies )) {word.replace( pos3, 3, 1, 'у' );return;Если слово кончается на "ies", как babies и cries, необходимо заменить "ies" на "y":279С++ для начинающих280}compare() возвращает 0, если две строки равны.
Первый аргумент, pos3, обозначаетначальную позицию, второй – длину сравниваемой подстроки (в нашем случае 3). Третийаргумент, ies, – строка-эталон. (На самом деле существует шесть вариантов функцииcompare(). Остальные мы покажем в следующем разделе.)replace() заменяет подстроку набором символов. В данном случае мы заменяемподстроку "ies" длиной в 3 символа единичным символом 'y'. (Имеется десятьперегруженных вариантов функции replace().