天天看点

STL学习(3)- string(2)以及stringstream

书接上文:STL学习(2)- string

详细讲一下string的其他用法,以及stringstream的用法。

append与replace

string s1 = s2 + s3;
           

上面这行代码能够运行是因为重载了+运算符,我们可以方便地拼接n个字符串并赋值。append函数就是标准的在string末尾拼接string的函数。准确地说是在末尾追加字符串或者字符。但是单独的+号只能完成拼接,如果想要对拼接的字符串选择一部分操作或者更多的功能,append函数能够满足大部分需求,而不需要先对拼接的字符串处理再拼接。下面是一些例子:

string s1 = "hello";
string s2 = "world";

s1.append(s2); // 就是s1 += s2,直接拼接
s1.append(s2,2,3); // s1后面拼接s2的子串,要求从下标为2开始的3个字符,即"rld"
s1.append("rua!",5); //在s1后拼接形参的前五个字符组成的子串
s1.append("rua!"); // 直接添加字符串
s3.append(233,'s');  // 在s3后面添加233个's'字符
           

replace,顾名思义是替换,先找再换。如果不使用replace,可以先利用迭代器与find函数找到位置,在进行字符串操作替换,非常麻烦。下面是一些用法:

string s1 = "hello";
string s2 = "world";

s1.replace(2,3,s2); // s1从下标9开始的5个字符被删除,同时在该位置插入s2,换而言之是下标9开始的5个字符换成了s2
s1.replace(1,3,s2,2,3); // s1从下标19开始的6个字符,被s2从下标7开始的6个字符替换
s1.replace(1,3,s2,3);  // s1从下标1开始的3个字符被s2的前3个字符替换。
s1.replace(1,2,"rua!"); // 同上,上面的额3种方法,s2均可直接换成字符串
s1.replace(2,3,3,'s'); // s1从下标2开始的3个字符被3个's'替换。
           

既然replace跟find有关,那么就一定跟迭代有关了。我们利用下标来确定操作位置,同样也可以用迭代器来操作,例如:

s1.replace(s1.begin()+2,s1.begin()+5,s2);
           

很简单,就是把原来的下标表示换成利用beign与end返回的指针值做锚,在内存上移动罢了。

compare

一般来说,我们想要比较2个字符串(字典顺序),或者看两个字符串是否相等,直接利用compare即可。其实compare还支持很多更精细的操作,例:

int ans = s1.compare(2,3,s2); // s1从下标2开始的3个字符与s2比较
int ans = s1.compare(2,3,s2,1,2); // s1从下标2开始的3个字符与s2从下标1开始的2个字符比较
// 同样,参数可以直接填字符串例:
int ans = s1.compare(2,3,"rua!",1,2);
           

string与int、double等数据类型的转换

一般来说,我们用itoa与atoi可以完成string与int的互相转化,这个是兼容C的一种做法。在VS上是会编译错误,所以对于C++是不推荐使用这2个函数的。我们可以利用字符串流,也就是stringstream更加方便快捷地完成转换操作。如果对itoa与atoi感兴趣可以自行百度,博主这里就不多说了,下面会主要介绍一下stringstream

stringstream

顾名思义,字符串流。一般的C++程序都会加载头文件iostream,表示io流。这样才能使用cin、cout等对象,方便快捷。stringstream跟iostream一样,只不过操作的对象由io(标准输入输出设备等)变成了string。那么我们也可以非常方便地对字符串进行处理,同时完成很重要的一个操作就是数据类型转换。

首先我们要先声明库:

#include<sstream>
           

然后就可以声明stringstream对象,利用<<与>>进行流操作。例:

stringstream ss;
string s1 = "hello world!";
string s2;

ss << s1;
ss >> s2;
           

这就是一个简单的string流操作,s1输入进流ss,在从流ss输出到s2。

关于stringstream的创建,上面的代码是常用的一种方法,另外还有一种直接初始化:

stringstream ss("rua!");
           

利用stringsteam进行数据类型转换

简单粗暴,将stirng或者其他数据类型输入进流,输出的时候输出到其他的数据类型,即可完成转换。

string str = "123";
stringstream ss;
ss << str;
int number;
ss >> number;
cout << number+1 << endl;
// ouput: 124
           

上面的代码完成了将字符串转换成为int类型。

int s = 123;
stringstream ss;
ss << s;
string str;
ss >> str;
cout << str + "dd" << endl;
// output: 123dd
           

上面的代码完成了将int类型转换为字符串。

想想我们在使用io流的时候,各种连续使用cout跟cin,没有发生混乱的情况。stringstream也一样,我们混着操作也完全可以,例如:

stringstream ss;
string s1 = "12 12.5 rua! string";
ss << s1;
int a;
double b;
string s2, s3;
ss >> a >> b >> s2 >> s3;
cout << a  << " " << b  << " " << s2  << " " << s3 << endl;
           

输出跟想的一样,流自动匹配格式进行赋值。

那么我们搞一些坏事,对于竞赛而言,完全不用考虑数据错误的情况,由于题目描述等,甚至第几个数据是什么数据类型都会明明白白写出来。但是实际上项目中输入的数据千奇百怪,那么stringstream该如何处理?看下面的代码:

stringstream ss;
string s1 = "12 12.5 rua! string";
ss << s1;
int a,b;
string s2, s3;
ss >> a >> b >> s2 >> s3;
cout << a  << " " << b  << " " << s2  << " " << s3 << endl;
           
// output: 12 12 .5 rua!
           

我们原来a跟b分别是int与double,而s1中也是一个int类型一个double类型。现在我们将b改成int类型,可以看到,12.5被分解了,读取小数点的时候,由于匹配的变量b是int类型,12赋值给了b,而小数点之后的并没有从流中消失,而是作为.12被字符串s2匹配了。那么s3就匹配了"rua!",最后剩下子串" string"仍然在流中。

stringstream的清空

一般来说clear()函数是清空,但是实际上内存却一直在增长。clear并不是完全清除缓存。所以我们需要重置这种操作。利用str方法来将缓存区重置为空的字符串(只有一个'\0')。像这样:

ss.str("");
           

这样,我们将字符串流的流变成"",等于是空的了。而clear()实际上并不是清除流内容,而是清空了状态。也就是说将流的状态重置了,而内容仍然存在。