C++(13)STL实践与分析之再谈String类型
2015-08-07 19:26
513 查看
STL实践与分析
--再谈string类型(上)引:
复习3.2节介绍的string类型:
曾经介绍过的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 | 把 s1和 s2串接起来,产生一个新的string对象 |
s1 += s2 | 将 s2拼接在 s1后面 |
关系操作符 | 相等运算(==和!=)以及关系运算(<、<=、>和>=)都可用于string对象的比较,等效于(区分大小写的)字典次序的比较 |
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、其他方法
构造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 个字符 |
注意:n、len2和 pos2都是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容器的操作不仅支持迭代器,而且提供下标为基础的操作。
与容器共用的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标记范围内所有的元素。返回一个迭代器,指向被删除元素段后面的第一个元素 |
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的副本 |
[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不能为b2,e2 |
S.replace(b,e,args) | 删除迭代器b 和e标记范围内所有的字符,用args替换之。返回s的引用 在这个版本中,args不能为s2,pos2,len2 |
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标记的范围内所有字符 |
[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定义为保证大于任何有效下标的值。
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的字符 |
string类型提供的find操作的参数 | |
---|---|
c,pos | 在s中,从下标pos标记的位置开始,查找字符c。pos的默认值为0 |
s2,pos | 在s中,从下标pos标记的位置开始,查找string对象s2。pos的默认值为0 |
cp,pos | 在s中,从下标pos标记的位置形参,查找指针cp所指向的C风格的以空字符结束的字符串。pos的默认值为0 |
cp,pos,n | 在s中,从下标pos标记的位置开始,查找指针cp所指向数组的前 n个字符。pos和n都没有默认值 |
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函数:
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个字符做比较 |
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
相关文章推荐
- C++(12)STL实践与分析之顺序容器
- C++(11)标准I/O库
- C++(10)函数
- C++(9)语句
- C语言枚举的用法
- C++(8)表达式
- C++(7)动态数组
- C++(6)C风格字符串
- [C/C++标准库]_[初级]_[std::vector的多线程读写问题]
- [C/C++标准库]_[初级]_[std::vector的多线程读写问题]
- C++(5)指针
- C++(4)数组
- C++(3)标准库类型
- eclipse报错lib32stdc++6
- C++(2)基本数据类型
- C++(1)入门
- 链表实现队列 c语言
- 一致性hash算法 C++语言实现
- [C++11 并发编程] 03 - 向线程传递参数
- redhat下配置c++开发环境