一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第20天,点击查看活动详情。
4、string类对象的修改操作
函数名称 | 功能说明 |
---|---|
push_back | 在字符串后尾插字符 c |
append | 在字符串后追加一个字符串 |
operator+= —— 重点 | 在字符串后追加字符串 str |
c_str —— 重点 | 返回 c 格式字符串 |
find + npos —— 重点 | 从字符串 pos 位置开始往后找字符 c,返回该字符在字符串中的位置 |
rfind | 从字符串 pos 位置开始往前找字符 c,返回该字符在字符串中的位置 |
substr | 在 str 中从 pos 位置开始,截取 n 个字符,然后将其返回 |
#include<string>
#include<iostream>
using namespace std;
void test_string1()
{
//1、push_back | append | operator +=
string s1("hello");
string s2("world");
s1.push_back('+');
s1.append("world");
cout << s1 << endl;
s1 += '+';
s1 += "bit+";
s1 += s2;
cout << s1 << endl;
cout << "----------cut----------" << endl;
//2、insert | erase
string s3("hello");
s3.insert(0, "bit ");
cout << s3 << endl;
//s3.erase(5);//从5删到nops
s3.erase(5, 2);//从5往后删2个
cout << s3 << endl;
cout << "----------cut----------" << endl;
}
void test_string2()
{
//要求取出文件的后缀
string file1("test.txt");
string file2("test.c");
string file3("test.txt.zip");//对test.txt文件打了个包
size_t pos1 = file1.find('.');
if(pos1 != string::npos)//当find的返回值不等于npos就找到了
{
//1、substr
string sub1 = file1.substr(pos1);//同substr(pos1, file1.size()-pos1);,但没必要,因为这里是取后缀,而substr有缺省参数npos
cout << sub1 << endl;
}
size_t pos2 = file2.find('.');
if(pos2 != string::npos)
{
string sub2 = file2.substr(pos2);
cout << sub2 << endl;
}
//由此可见对于file3,以上代码不适用
size_t pos3 = file3.find('.');
if(pos3 != string::npos)
{
string sub3 = file3.substr(pos3);
cout << sub3 << endl;
}
//更适用的来说取文件的后缀应当使用另一个接口rfind
size_t pos4 = file3.rfind('.');
if(pos4 != string::npos)
{
string sub4 = file3.substr(pos4);
cout << sub4 << endl;
}
cout << "----------cut----------" << endl;
}
void test_string3()
{
//取出url中的protocol、domain、uri ———— 网址 = 协议 + 域名 + 资源定位
string url("http://www.cplusplus.com/reference/string/string/find/");
size_t i1 = url.find("://");//find也可以找串
if(i1 != string::npos)
{
string protocol = url.substr(0, i1 - 0);
cout << "protocol:" << protocol << endl;
}
size_t i2 = url.find('/', i1 + 3);//find的第四个版本
if(i2 != string::npos)
{
string domain = url.substr(i1 + 3, i2 - (i1 + 3));
cout << "domain:" << domain << endl;
}
size_t i3 = url.find('/', i2);
if(i3 != string::npos)
{
string uri = url.substr(i3);
cout << "uri:" << uri << endl;
printf("uri:%s\n", uri.c_str());//C语言去输出string做不到,但是提供了c_str
}
}
int main()
{
test_string1();
//3、find
test_string2();
test_string3();
return 0;
}
📝说明
push_back | append | operator+= ❗
如果你要尾插一个字符用 push_back,如果你要尾插一个字符串用 append。个人感觉这是 string 设计的不好的地方,为什么不再重载一个 push_back 呢,非要去搞一个 append 来恶心人,而 append 又重载了六个版本,也没啥太大的价值,比较常用的也就三、四版本。
相对于 push_back、append 更推荐使用 operator+=,因为它可以追加一个字符,也可以追加一个字符串,还可以追加一个对象。
这里我们发现 string 里面没有头插、头删,但它有中间插入、删除。 insert | erase ❗
可以看到实现了七个版本,这里就了解了解较为常用的,其余简单提一下。
它不仅仅可以中间插入、也可以在头上插入,还可以在尾部插入。
但是对于 insert 能不用就不用,因为效率比较低,它需要挪动数据。 与 insert 对应的是 erase。 erase 的第一个版本参数中的 npos 比较特殊,它给的是一个缺省参数,nops 是这个类里的静态成员变量,它是 -1,但实际上不是 -1,因为这个 -1 给了 size_t,所以它转换为补码就是整型的最大的值。 find | rfind ❗
对于 find 的返回值,一般是 int,找到返回下标,找不到返回 -1。这里用 size_t 的想法是,找到返回下标,找不到会返回 nops,但是正常的字符不可能有那么长。 查找字符串中内容的最后一次出现:
substr ❗
生成子串。 c_str ❗
它可以和 C语言配合使用。
5、string类非成员函数
函数 | 功能说明 |
---|---|
operator+ | 尽量少用,因为传值返回,导致深拷贝效率低 |
operator>> —— 重点 | 输入运算符重载 |
operator<< —— 重点 | 输出运算符重载 |
getline —— 重点 | 获取一行字符串 |
relational operators —— 重点 | 大小比较 |
#include<string>
#include<iostream>
using namespace std;
int main()
{
string s1("hello");
s1 + "world";
cout << s1 << endl;
s1 += "world";
cout << s1 << endl;
cout << "----------cut----------" << endl;
return 0;
}
📝说明
operator+ 和 operator+= ❗
它们的作用都是尾插,但是 operator+= 会改变当前字符串,而 operator+ 不改变当前字符串。 relational operators ❗
string 还提供了比较大小的接口,可以看到非常多的版本,比如对象跟对象比、字符串跟对象比,自我感觉比较冗余。
因为字符串是可以被隐式类型转换成 string 的:
string s1("hello");//正常写法,string支持单参数的构造函数
string s2 = "world";//隐式类型转换,先将字符串构造一个string,再将string拷贝构造s2。最后优化成直接构造
所以这里是想说就算是字符串跟对象比,字符串也可以隐式转换成对象,没必要再实现一个版本。
6、补充
函数 | 功能说明 |
---|---|
to_string | 数值转字符串 |
stoi | 字符串转数值 |
#include<string>
#include<iostream>
using namespace std;
int main()
{
int i = 1234;
string str = to_string(i);
cout << str << endl;
int j = stoi(str);
cout << j << endl;
return 0;
}
📝说明
to_string | stoi ❗
将数值转换为字符串(注意它不是 string 的成员函数,而是全局函数): 在 C语言中有类似的函数 itoa,它需要自己提供空间,且有些 OJ 上还不支持,因为它不是标准的 C库,所以不够好用。
可以看到它还提供了将字符串转成整数: