您的位置:首页 > 编程语言 > C语言/C++

C++(13)STL实践与分析之再谈String类型

2015-08-07 19:26 513 查看

STL实践与分析

--再谈string类型(上)

引:

复习3.2节介绍的string类型:
[thead]
[/thead]

曾经介绍过的string操作
string s;
定义一个新的空string对象,命名为s
string s(cp);
定义一个新的string对象,cp所指向的(以空字符null结束的)C风格字符串初始化该对象
string s(s2);
定义一个新的string对象,并将它初始化为s2的副本
is >> s;
从输入流is中读取一个以空白字符分隔的字符串,写入s
os << s;
s写到输出流os
getline(is,s);
从输入流is读取一行字符,写入s
s1 + s2
s1s2串接起来,产生一个新的string对象
s1 += s2
s2拼接在 s1后面
关系操作符
相等运算(==!=)以及关系运算(<<=>>=)都可用于string对象的比较,等效于(区分大小写的)字典次序的比较
在某些方面,可以将string类型视为字符容器,除了一些特殊的操作,string类型提供与vector类型相同的操作。

string容器支持的操作:

1)表9.5 列出的typedef,包括迭代器类型。

2)表9.2列出的容器构造函数,但是不包括只需要一个长度参数的构造函数。

3)表9.7列出的vector容器所提供的添加元素的操作。注意:无论vector容器还是string类型都不支持push_front操作。

4)表9.8 列出的长度操作。

5)表9.9列出的下标和at操作;但string类型不提供该表列出的back和front操作。

6)表9.6 列出的begin 和end 操作。

7)表9.10列出的erase和clear操作;但是string类型不入提供pop_back或pop_front操作。

8)表9.11 列出的赋值操作。

9)与vector容器的元素一样,string的字符也是连续存储的。因此,string类型支持capacity和reserve操作。

[cpp] view
plaincopy





string str("Hiyal");

string::iterator iter = str.begin();



while (iter != str.end())

{

cout << *iter ++ << endl;

}

除了共享容器的操作外,string类型还支持其他本类型特有的操作。

[cpp] view
plaincopy





//P290 习题9.34

int main()

{

// freopen("input","r",stdin);

string lower;

while (cin >> lower)

{

for (string::iterator iter = lower.begin(); iter != lower.end(); ++iter)

{

*iter = toupper(*iter);

}

cout << lower << endl;

}

}

[cpp] view
plaincopy





//习题 9.35

int main()

{

//freopen("input","r",stdin);

string str;

while (cin >> str)

{

for (string::iterator iter = str.begin(); iter != str.end(); ++iter)

{

if (isupper(*iter))

{

str.erase(iter);

--iter;

}

}

cout << str << endl;

}

}

[cpp] view
plaincopy





//习题9.36

int main()

{

vector<char> cVec;

char c;

while (cin >> c)

{

cVec.push_back(c);

}



string s(cVec.begin(),cVec.end());

cout << s << endl;

}

[cpp] view
plaincopy





//习题9.37

int main()

{

string s;

s.reserve(100); //为其先开辟一块内存

char c;

while (cin >> c)

{

s.push_back(c);

}

cout << s << endl;

}

一、构造string对象的方法

1、构造string对象传统方法

[cpp] view
plaincopy





string s1;

string s2(5,'a');

string s3(s2);

string s4(s3.begin(),s3.begin() + s3.size()/2);



char *cp = "HiHa";

char c_array[] = "Hello World";

char no_null[] = {'H','i'};



string str1(cp);

string str2(c_array,5);

string str3(c_array+5,4);

string str4(no_null); //Error

string str5(no_null,2);

cout << str4 << endl;

将不包含null的数组传递给stringstr(cp)将导致编译器无法检测到的严重错误,此类错误在运行时会发生什么情况没有定义。

2、其他方法
[thead]
[/thead]

构造string对象的其他方法
String s(cp,n);
创建一个string对象,它被初始化为cp所指向数组的前n个元素的副本
Strings(s2,pos2);
创建一个string对象,它被初始化为一个已存在的string对象s2从下标pos2开始的字符的副本
Strings(s2,pos2,len2);
创建一个string对象,它被初始化为s2中从下标pos2开始的len2个字符的副本。如果pos2>
s2.size(),
则该操作未定义,无论len2的值是多少,最多只能复制s2.size()-
pos2
个字符
注意:nlen2pos2都是unsigned
用子串做初始化式:

[cpp] view
plaincopy





string str1("HiHa");

string str2(str1,2);

cout << str2 << endl;



string str3(str1,0,2);

cout << str3 << endl;



string str4(str1,0,8);

cout << str4 << endl;

无论要求复制多少个字符,标准库最多只能复制数目与string对象长度相等的字符。

二、修改string对象的其他方法

1、string容器的操作不仅支持迭代器,而且提供下标为基础的操作。
[thead]
[/thead]

与容器共用的string操作
s.insert(p,t)
在迭代器p指向的元素之前插入一个值为t的新元素。返回指向新插入元素的迭代器

s.insert(p,n,t)
在迭代器p指向的元素之前插入n个值为t的新元素。返

回 void
s.insert(p,b,e)
在迭代器 p指向的元素之前插入迭代器b 和e 标记范围内

所有的元素。返回void

s.assign(b,e)
在迭代器b和e标记范围内的元素替换s。对于string类型,该操作返回s;对于容器类型,则返回void

s.assign(n,t)
用值为t的n个副本替换s。对于string类型,该操作返回s;对于容器类型,则返回void

s.erase(p)
删除迭代器 p指向的元素。返回一个迭代器,指向被删除元素后面的元素
s.erase(b,e)
删除迭代器b和e标记范围内所有的元素。返回一个迭代器,指向被删除元素段后面的第一个元素
[thead]
[/thead]

string类型特有的操作
s.insert(pos,n,c)
在下标为pos元素之前插入n个字符c

s.insert(pos,s2)
在下标为pos的元素之前插入string对象s2副本
s.insert(pos,s2,pos2,len2)
在下标为pos的元素之前插入s2从下标pos2开始的len2个字符

s.insert(pos,cp,len)
在下标为pos的元素之前插入cp所指向数组的前len个字符
s.insert(pos,cp)
在下标为pos的元素之前插入cp所指向的以空字符结束的字符串副本

s.assign(s2)
s2的副本替换s

s.assign(s2,pos2,len)
s2从下标pos2开始的len个字符副本替换s

a.assign(cp,len)
cp所指向数组的len个字符副本替换s

a.assign(cp)
cp所指向的以空字符结束的字符串副本替换s
a.erase(pos,len)
删除从下标pos开始的 len个字符

除非特殊声明,上述所有操作都返回s的引用
基于位置的实参

对于string类型,还允许通过为erase函数传递一个起点位置和删除元素的数目,来指定删除的范围:

[cpp] view
plaincopy





str.erase(str.size()-5,5);

类似的,对于string类型,还可以使用下标而不是迭代器来指定插入位置:

[cpp] view
plaincopy





str.insert(str.size(),5,'!');

指定新的内容

在string对象中,insert或assign的字符可来自字符数组或者另一个string对象。

[cpp] view
plaincopy





char *cp = "Stately plump Buck";

string s;

s.assign(cp,7);

s.insert(s.size(),cp+7);

cout << s << endl;

类似的,可以将一个string对象的副本插入到另一个string对象中去:

[cpp] view
plaincopy





//可以支持三种插入方式

string str1("some string");

string str2("some other string");



str1.insert(str1.begin(),str2.begin(),str2.end());

str1.insert(0,str2);

str1.insert(0,str2,0,str2.size());

cout << str1 << endl;



三、只适用于string类型的操作

string类型提供了容器类型不支持的其他几种操作,如下标所示:

substr函数,返回当前string对象的子串。

append和replace函数,用于修改string对象

一系列的find函数,用于查找string对象

substr操作

子串操作
S.substr(pos,n)
返回一个string类型的字符串,他包含s中从下标pos开始的n个字符
S.substr(pos)
返回一个string类型的字符串,他包含s中从下标pos开始到s末尾的所有字符
S.substr()
返回s的副本
我们可以给substr函数传递一个查找的起点和一个计数器。该函数将生成一个新的string对象,而字符数目由计数器决定,但最多只能到原string对象的最后一个字符!

[cpp] view
plaincopy





string s("Hello World");

string str = s.substr(6,5);

cout << str << endl;

另一种方式:

[cpp] view
plaincopy





string str = s.substr(6);

append和replace函数

string类型提供了6个append重载函数和10个replace版本O(∩_∩)O~。append和replace函数使用了相同的参数集合实现重载(如下表所示)。

对于append操作,字符将添加在string对象的末尾,而replace函数则将这些字符插入到指定位置,从而替换string对象中一段已经存在的字符。
修改string对象的操作(args在下表定义)
S.append(args)
将args串接在s后面,返回s的引用
S.replace(pos,len,args)
删除s中从下标开始的len个字符,用args指定的字符串替换之,返回s的引用。

在这个版本中,args不能为b2e2
S.replace(b,e,args)
删除迭代器b 和e标记范围内所有的字符,用args替换之。返回s的引用

在这个版本中,args不能为s2pos2len2
append和replace操作的参数args
s2
string类型的字符串 s2
s1,pos2,len2
字符串s2 中从下标pos2 开始的len2 个字符
cp
指针cp指向的以空字符结束的数组
cp,len2
cp指向的以空字符结束的数组中前len2 个字符
n,c
字符c 的n 个副本
b2,e2
迭代器b2 和e2标记的范围内所有字符
append操作提供了在字符串尾部插入的捷径:

[cpp] view
plaincopy





string str("C++ Primer");

str.append(" 3rd Ed.");

//与下列操作作用相同

str.insert(str.size()," 3rd Ed.");

replace操作用于删除一段指定范围内的字符,然后在删除的位置插入一组新的字符,等效于调用erase和insert函数:

[cpp] view
plaincopy





str.replace(11,3,"4th");

cout << str << endl;

//与下列操作作用相同

str.erase(11,3);

str.insert(11,"4th");

【注释:】

并不要求删除的文本长度与插入的长度一定相同。

[html] view
plaincopy





//只删除了3个字符,但是在同一个位置却插入了6个字符。

str.replace(11,3,"Fourth");


STL实践与分析

--再谈string类型(下)

四、string类型的查找操作

string类型提供了6种查找函数,每种函数以不同形式的find命名。这些操作全部返回string::size_type类型的值,以下标的方式标记查找匹配所发生的位置;或者返回一个string::npos的特殊值,说明查找没有匹配。string类将npos定义为保证大于任何有效下标的值。
[thead]
[/thead]

string类型的查找操作(参数在下表定义)
s.find(args)
s中查找args的第一次出现
s.rfind(args)
s中查找args的最后一次出现
s.find_first_of(args)
s中查找args的任意字符的第一次出现
s.find_last_of(args)
s中查找args的任意字符的最后一次出现
s.find_first_not_of(args)
s中查找第一个不属于args的字符
s.find_last_not_of(args)
s中查找最后一个不属于args的字符
每种查找都有4个重载版本,每个版本使用不同的参数集合。这些操作的不同之处在于查找的到底是单个字符、另一个string字符串、C风格的以空字符结束的字符串,还是用字符数组给出的特定数据的字符集合。
[thead]
[/thead]

string类型提供的find操作的参数
c,pos
s,从下标pos标记的位置开始,查找字符cpos的默认值为0
s2,pos
s,从下标pos标记的位置开始,查找string对象s2pos的默认值为0
cp,pos
s,从下标pos标记的位置形参,查找指针cp所指向的C风格的以空字符结束的字符串。pos的默认值为0
cp,pos,n
s,从下标pos标记的位置开始,查找指针cp所指向数组的前 n个字符。posn都没有默认值
1、精确匹配查找

find函数,如果找到的话,则返回第一次匹配的下标值;如果找不到,则返回npos:

[html] view
plaincopy





string name("AnnaBelle");
string::size_type pos = name.find("Anna");

默认情况下,find操作以及其他处理字符的string操作使用内置操作符比较string字符串中的字符。因此,这些操作(以及其他string操作)都区分字母的大小写;

[html] view
plaincopy





string lowerCase("annabelle");

string::size_type pos = lowerCase.find("Anna");

if (pos != string::npos)

{

cout << lowerCase[pos] << endl;

}

find操作的返回类型是string::size_type类型,请使用该类型的对象存储find的返回值。

2、查找任意字符

[html] view
plaincopy





//在name中寻找并定位第一个数字

string numeric("1234567890");

string name("r2d2");

string::size_type pos = name.find_first_of(numeric);

cout << pos << endl

<< name[pos] << endl;

【谨记:】

string对象的元素下标从0开始计数;

3、指定查找的起点

程序员可以给find操作传递一个可选的起点位置实参,用于指定开始查找的下标位置,该位置实参的默认值为0。通常的编程模式是使用这个可选的实参循环查找string对象中所有的匹配。

[html] view
plaincopy





//重写查找“r2d2”的程序,以便找出 name 字符串中出现的所有数字:

string numeric("0123456789");

string name("r2d25");

string::size_type pos = 0;



while ((pos = name.find_first_of(numeric,pos)) != string::npos)

{

cout << name[pos] << endl;

++ pos;

}

pos必须+1,以确保下一次循环从刚找到的数字后面开始查找下一个数字。

4、寻找不匹配点

调用find_first_not_of函数查找第一与实参不匹配的位置:

[html] view
plaincopy





//在 string 对象中寻找第一个非数字字符

string numeric("1234567890");

string dept("03714p3");

string::size_type pos = dept.find_first_not_of(numeric);

if (pos != string::npos)

{

cout << dept[pos] << endl;

}

5、反向查找

迄今为止,我们使用的所有find操作都是从左向右查找的。除此之外,标准库还提供了一组类似的从右向左查找string对象的操作。Rfind成员函数用于寻找最后一个–
也就是最右边 – 制定子串出现的位置:

[html] view
plaincopy





string river("Miississippi");

string::size_type first_pos = river.find("is");

if (first_pos != string::npos)

{

cout << "first_pos: " << first_pos << endl;

}



string::size_type last_pos = river.rfind("is");

if (last_pos != string::npos)

{

cout << "last_pos: " << last_pos << endl;

}

6、find_last函数

find_last函数类似对应的find_first函数,唯一的差别在于find_last函数返回最后一个匹配的位置,而不是第一个

1)find_last_of函数查找与目标字符串的任意字符匹配的最后一个字符。

2)find_last_not_of函数查找最后一个不能跟目标字符串的任何字符匹配的字符。

这两个操作都提供第二个参数,这个参数是可选的,用于指定在string对象中开始查找的位置。

[html] view
plaincopy





//P297 习题9.38

//(1)

string str("ab2c3d7R4E6");

string numeric("0123456789");

string::size_type pos = 0;



while ((pos = str.find_first_of(numeric,pos)) != string::npos)

{

cout << str[pos] << endl;

++ pos;

}

[cpp] view
plaincopy





//(2)

string str("ab2c3d7R4E6");

string numeric("0123456789");

string::size_type pos = 0;



while ((pos = str.find_first_not_of(numeric,pos)) != string::npos)

{

cout << str[pos] << endl;

++ pos;

}

[cpp] view
plaincopy





//习题9.39

#include <iostream>

#include <sstream>

#include <stack>

using namespace std;



int main()

{

string line1 = "We were her pride of 10 she named us:";

string line2 = "Benjamin, Phoenix, the Prodigal";

string line3 = "and perspicacious pacific Suzanne";



string sentence = line1 + ' ' + line2 + ' ' + line3;

istringstream item(sentence);



unsigned int shoest = 1000;

unsigned int lonest = 0;



stack<string> shoSta;

stack<string> lonSta;

string word;



int wordCnt = 0;

while (item >> word)

{

++ wordCnt;

if (word.size() > lonest)

{

lonest = word.size();

while (!lonSta.empty())

{

lonSta.pop();

}

lonSta.push(word);

}

else if (word.size() == lonest)

{

lonSta.push(word);

}



if (word.size() < shoest)

{

shoest = word.size();

while (!shoSta.empty())

{

shoSta.pop();

}

shoSta.push(word);

}

else if(word.size() == shoest)

{

shoSta.push(word);

}

}

cout << wordCnt << endl;



cout << endl << "Longest Word:" << endl;

while (!lonSta.empty())

{

cout << lonSta.top() << endl;

lonSta.pop();

}



cout << endl << "Shortest Word:" << endl;

while (!shoSta.empty())

{

cout << shoSta.top() << endl;

shoSta.pop();

}

}

五、string对象的比较

1、传统的操作符比较

string类型定义了所有关系操作符,使程序员可以比较两个string对象是否相等(==)、不等(!=),以及实现小于或大于(<、<=、>、>=)运算。string对象采用字典顺序比较,也就是说,string对象的比较与大小写敏感的字典顺序比较相同

2、compare函数

操作的结果类似于C语言中的strcmp函数:
[thead]
[/thead]

string类型的compare操作
s.compare(s2)
比较s和s2
s.compare(pos1,n1,s2)
让s中从pos下标位置开始的n1个字符与s2做比较
s.compare(pos1,n1,s2,pos2,n2)
让s中从pos1下标位置开始的n1个字符与s2中从pos2下标位置开始的n2个字符做比较
s.compare(cp)
比较s和cp所指向的以空字符结束的字符串
s.compare(pos1,n1,cp)
让s中从pos1下标位置开始的n1个字符与cp所指向的字符串做比较
c.compare(pos1,n1,cp,n2)
让s中从pos1下标位置开始的n1个字符与cp所指向的字符丰的前n2个字符做比较
compare函数返回下面列出的三种可能值之一:

1)正数,此时s1大于 args所代表的string对象。

2)负数,此时s1小于 args所代表的string对象。

3)0,此时 s1恰好等于 args所代表的string对象。

[html] view
plaincopy





string cobol_program_crash("abend");

string cplus_program_crash("abort");



cout << cobol_program_crash.compare(cplus_program_crash) << endl;

cout << cplus_program_crash.compare(cobol_program_crash) << endl;

compare函数提供了6个重载版本,方便程序员实现一个或两个string对象的子串的比较,以及string对象与字符数组或其中一部分的比较:

[html] view
plaincopy





char second_ed[] = "C++ Primer, 2nd Edition";

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

string fourth_ed("C++ Primer, 4th Edition");



cout << fourth_ed.compare(second_ed) << endl;

cout << fourth_ed.compare(fourth_ed.find("4th"),3,

third_ed,third_ed.find("3rd"),3)

<< endl;

[html] view
plaincopy





//P299 习题9.40

int main()

{

string q1("When lilacs last in the dooryard bloom`d");

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

string sentence;

sentence.assign(q2,0,12);

sentence.append(q1,16,16);

cout << sentence << endl;

}

[html] view
plaincopy





//习题9.41

string greet(string form,string lastname,string title,

string::size_type pos,int length)

{

string::iterator beg,end;



beg = form.begin() + form.find("Daisy");

end = beg + 5;



form.replace(beg,end,lastname);



beg = form.begin() + form.find("Ms");

end = beg + 2;



form.replace(beg,end,title.substr(pos,length));



return form;

}

/*

string greet(string form,string lastname,string title,

string::size_type pos,int length)

{

form.replace(form.find("Daisy"),5,lastname);

form.replace(form.find("Ms"),2,title,pos,length);



return form;

}

*/

int main()

{

string generic1("Dear Ms Daisy:");

string generic2("MrsMsMisssPeople");

string lastName("AnnaP");

string salute = greet(generic1,lastName,generic2,5,4);

cout << salute << endl;

}

本文借鉴:http://blog.csdn.net/column/details/zjf666.html?&page=4
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: