Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих.pdf
Скачиваний:
183
Добавлен:
01.05.2014
Размер:
3.97 Mб
Скачать

string ses( "ses" );

if ( ! word.compare( pos3, 3, ses ))

{

word.erase( pos3+l, 2 ); return;

}

Если слово кончается на "ous", как oblivious, fulvous, cretaceous, или на "is", как genesis, mimesis, hepatitis, мы не будем изменять его. (Наша система несовершенна. Например, в слове kiwis надо убрать последнее 's'.) Пропустим и слова, оканчивающиеся на "ius" (genius) или на "ss" (hiss, lateness, less). Нам поможет

string::size_type spos = 0; string::size_type pos3 = word.size()-3;

// "ous", "ss", "is", "ius" string suffixes( "oussisius" );

if ( ! word.compare( pos3, 3, suffixes, spos, 3

) ||

//

ous

3 ) ||

//

! word.compare( pos3, 3, suffixes, spos+6,

ius

 

 

!word.compare( pos3+l, 2, suffixes, spos+2, 2 ) || // ss

!word.compare( pos3+l, 2, suffixes, spos+4, 2 ) ) // is

вторая форма функции compare(): return;

// удалим последнее 's'

В противном случае удалим последнее 's': word.erase( pos3+2 );

Имена собственные, например Pythagoras, Brahms, Burne-Jones, не подпадают под общие правила. Этот случай мы оставим как упражнение для читателя, когда будем рассказывать об ассоциативных контейнерах.

Но прежде чем перейти к ним, рассмотрим оставшиеся строковые операции. Упражнение 6.17

Наша программа не умеет обрабатывать суффиксы ed (surprised), ly (surprisingly) и ing (surprisingly). Реализуйте одну из функций для этого случая:

(a) suffix_ed() (b) suffix_ly()

(c) suffix_ing()

6.11. Дополнительные операции со строками

Вторая форма функции-члена erase() принимает в качестве параметров два итератора, ограничивающих удаляемую подстроку. Например, превратим

string name( "AnnaLiviaPlurabelle" );

typedef string::size_type size_type; size_type startPos = name.find( 'L' ) size_type endPos =

name.find_1ast_of( 'b' );

name.erase( name.begin()+startPos,

в строку "Annabelle": name.begin()+endPos );

Символ, на который указывает второй итератор, не входит в удаляемую подстроку.

Для третьей формы параметром является только один итератор; эта форма удаляет все символы, начиная с указанной позиции до конца строки. Например:

name.erase( name. begin()+4 );

оставляет строку "Anna".

Функция-член insert() позволяет вставить в заданную позицию строки другую строку или символ. Общая форма выглядит так:

string_object.insert( position, new_string );

position обозначает позицию, перед которой производится вставка. new_string может

string string_object( "Missisippi" ); string::size_type pos =

string_object.find( "isi" );

быть объектом класса string, C-строкой или символом: string_object.insert( pos+1, 's' );

string new_string ( "AnnaBelle Lee" ); string_object += ' '; // добавим пробел

// найдем начальную и конечную позицию в new_string pos = new_string.find( 'B' );

string::size_type posEnd = new_string.find( ' ' );

string_object.insert(

string_object.size(),

// позиция вставки

new_string, pos,

// начало подстроки в

new_string

// конец подстроки new_string

posEnd

Можно выделить для вставки подстроку из new_string:

)

string_object получает значение "Mississippi Belle". Если мы хотим вставить все символы new_string, начиная с pos, последний параметр нужно опустить.

string

sl( "Mississipp i" );

Пусть есть две строки:

string s2( "Annabelle" );

Как получить третью строку со значением "Miss Anna"?

string s3;

// скопируем первые 4 символа s1

Можно использовать функции-члены assign() и append(): s3.assign ( s1, 4 );

// добавим

пробе

л

s3 теперь содержит значение "Miss".

s3 += ' ';

// добавим 4 первых символа s2

Теперь s3 содержит "Miss ". s3.append(s2,4);

s3 получила значение "Miss Anna". То же самое можно сделать короче:

s3.assign(s1,4).append(' ').append(s2,4);

Другая форма функции-члена assign() имеет три параметра: второй обозначает позицию начала, а третий – длину. Позиции нумеруются с 0. Вот как, скажем, извлечь

string beauty;

// присвоим beauty значение "belle"

"belle" из "Annabelle": beauty.assign( s2, 4, 5 );

Вместо этих параметров мы можем использовать пару итераторов:

// присвоим beauty значение "belle"

beauty.assign( s2, s2.begin()+4, s2.end() );

В следующем примере две строки содержат названия текущего проекта и проекта, находящегося в отложенном состоянии. Они должны периодически обмениваться

string current_project( "C++ Primer, 3rd Edition" );

значениями, поскольку работа идет то над одним, то над другим. Например: string pending_project( "Fantasia 2000, Firebird segment" );

Функция-член swap() позволяет обменять значения двух строк с помощью вызова

current_project.swap( pending_project );

Для строки

string first_novel( "V" );

операция взятия индекса

char ch = first_novel[ 1 ];

возвратит неопределенное значение: длина строки first_novel равна 1, и единственное правильное значение индекса – 0. Такая операция взятия индекса не обеспечивает проверку правильности параметра, но мы всегда можем сделать это сами с помощью

int

elem_count( const string &word, char elem )

{

int occurs = 0;

// не надо больше проверять ix

for ( int ix=0; ix < word.size(); ++- ix )

if ( word[ ix ] == elem ) ++occurs;

return occurs;

функции-члена size():

}

Там, где это невозможно или нежелательно, например:

void

mumble( const string &st, int index )

{

//возможна ошибка char ch = st[ index ];

//...

}

следует воспользоваться функцией at(), которая делает то же, что и операция взятия индекса, но с проверкой. Если индекс выходит за границу, возбуждается исключение

void

mumble( const string &st, int index )

{

try {

char ch = st.at( index ); // ...

}

catch ( std::out_of_range ){...} // ...

out_of_range:

}

string

cobol_program_crash( "aben d" );

Строки можно сравнивать лексикографически. Например: string cplus_program_crash( "abort" );

Строка cobol_program_crash лексикографически меньше, чем cplus_program_crash: сопоставление производится по первому отличающемуся символу, а буква e в латинском алфавите идет раньше, чем o. Операция сравнения выполняется функцией-членом compare(). Вызов

sl.compare( s2 );

возвращает одно из трех значений:

если s1 больше, чем s2, то положительное;

если s1 меньше, чем s2, то отрицательное;

если s1 равно s2, то 0.

Например,

cobol_program_crash.compare( cplus_program_crash );

вернет отрицательное значение, а

cplus_program_crash.compare( cobol_program_crash );

положительное. Перегруженные операции сравнения (<, >, !=, ==, <=, >=) являются более компактной записью функции compare().

Шесть вариантов функции-члена compare() позволяют выделить сравниваемые подстроки в одном или обоих операндах. (Примеры вызовов приводились в предыдущем разделе.)

Функция-член replace() дает десять способов заменить одну подстроку на другую (их длины не обязаны совпадать). В двух основных формах replace() первые два аргумента задают заменяемую подстроку: в первом варианте в виде начальной позиции и длины, во втором – в виде пары итераторов на ее начало и конец. Вот пример первого

string sentence(

"An ADT provides both interface and implementation." );

string::size_type position = sentence.find_1ast_of( 'A' ); string::size_type length = 3;

// заменяем ADT на Abstract Data Type

варианта:

sentence.repiace( position, length, "Abstract Data Type" );

position представляет собой начальную позицию, а length – длину заменяемой подстроки. Третий аргумент является подставляемой строкой. Его можно задать

string new_str( "Abstract Data Type" );

несколькими способами. Допустим, как объект string: sentence.replace( position, length, new_str );

#include <string>

typedef string::size_type size_type;

// найдем позицию трех букв size_type posA = new_str.find( 'A' ); size_type posD = new_str.find( 'D' ); size_type posT = new_str.find( 'T' );

// нашли: заменим T на "Type" sentence.replace( position+2, 1, new_str, posT,

4);

//нашли: заменим D на "Data " sentence.replace( position+1, 1, new_str, posD,

5);

//нашли: заменим A на "Abstract "

Следующий пример иллюстрирует выделение подстроки в new_str:

sentence.replace( position, 1, new_str, posA, 9 );

Еще один вариант позволяет заменить подстроку на один символ, повторенный заданное

string hmm( "Some celebrate Java as the successor to C+ +." );

string:: size_type position = hmm.find( 'J' ); // заменим Java на xxxx

количество раз:

hmm.repiace( position, 4, 'x', 4 );

В данном примере используется указатель на символьный массив и длина вставляемой

const char *lang = "EiffelAda95JavaModula3"; int index[] = { 0, 6, 11, 15, 22 };

string ahhem(

"C++ is the language for today's power programmers." );

подстроки:

ahhem.replace(0, 3, lang+index[1], index[2]-index[1]);

string sentence(

"An ADT provides both interface and implementation." );

// указывает на 'A' в ADT

string: iterator start = sentence. begin()+3;

//заменяем ADT на Abstract Data Type

Аздесь мы используем пару итераторов:

sentence.repiace( start, start+3, "Abstract Data Type" );

Оставшиеся четыре варианта допускают задание заменяющей строки как объекта типа string, символа, повторяющегося N раз, пары итераторов и C-строки.

Вот и все, что мы хотели сказать об операциях со строками. Для более полной информации обращайтесь к определению стандарта С++ [ISO-C++97].

Упражнение 6.18

Напишите программу, которая с помощью функций-членов assign() и append() из

string quote1( "When lilacs last in the dooryard bloom'd" );

строк

string quote2( "The child "is father of the man" );

составит предложение

"The child is in the dooryard"