
🔥小叶-duck:个人主页
❄️个人专栏:《Data-Structure-Learning》
✨未择之路,不须回头
已择之路,纵是荆棘遍野,亦作花海遨游
目录
[一、string 类0基础上手:常见核心接口使用(附实操代码及注释)](#一、string 类0基础上手:常见核心接口使用(附实操代码及注释))
[1.1 尾部追加:3种方式对比(operator+=/push_back/append)](#1.1 尾部追加:3种方式对比(operator+=/push_back/append))
[1.2 插入和删除:insert 和 erase 在指定位置插入删除](#1.2 插入和删除:insert 和 erase 在指定位置插入删除)
[1.3 字符串替换:replace() 修改指定位置内容](#1.3 字符串替换:replace() 修改指定位置内容)
[2.1 字符串查找:find() 找字符/子串](#2.1 字符串查找:find() 找字符/子串)
[2.2 子串截取:substr() 从指定位置取指定长度](#2.2 子串截取:substr() 从指定位置取指定长度)
[2.3 C字符转换:c_str () 适配C语言库函数](#2.3 C字符转换:c_str () 适配C语言库函数)
[2.4 整行输入:getline() 读取带空格的字符串](#2.4 整行输入:getline() 读取带空格的字符串)
前言
基于上篇文章C++ string 类使用超全攻略(上):创建、遍历及容量操作深度解析的常见核心接口我们继续进行讲解。
一、string 类0基础上手:常见核心接口使用(附实操代码及注释)
1、字符串修改:高频操作(拼接/插入/删除/清空)
|--------------------------------------------------------------------------------------------------|---------------|
| 函数名称 | 功能说明 |
| push_back | 在字符串后尾插字符c |
| append | 在字符串后追加一个字符串 |
| operator+= (重点) | 在字符串后追加字符串str |
| insert(重点) | 在指定位置插入数据 |
| erase(重点) | 在指定位置删除数据 |
| replace | 修改指定位置内容 |
1.1 尾部追加:3种方式对比(operator+=/push_back/append)
尾部追加是我们比较常见的修改场景,3中方式各有优势,大家可以按需选择:
operator+= :支持追加单个字符和字符串,比 push_back 和 append 更加灵活;
push_back :仅支持单个字符,功能单一,适合明确追加单个字符的场景;
append:仅支持字符串、子串,适合需要追加部分内容的场景。
cpp
void Test_string4()
{
//字符串修改
//尾部追加(operator+=/push_back/append)
string s1("Hello world");
s1.push_back('a'); //仅尾插一个字符
cout << s1 << endl;
s1.append("bdc"); //仅尾插一个字符串
cout << s1 << endl;
s1.append(10, 'x'); //尾插10个x
cout << s1 << endl << endl;
string s2("Hello"); //使用 += 更加方便
s2 += ' ';
s2 += "world";
cout << s2 << endl << endl;
}
int main()
{
Test_string4();
return 0;
}
1.2 插入和删除:insert 和 erase 在指定位置插入删除
cpp
void Test_string4()
{
//插入和删除:insert 和 erase
string s3("Hello world");
//头插数据:
s3.insert(0, "abc ");
cout << s3 << endl;
//指定位置之前插入数据:
s3.insert(4, "def "); //注意的是 pos 是下标
cout << s3 << endl;
//插入单个字符(insert设计比较有缺陷)
//string& insert(size_t pos, size_t n, char c);
//n > 1时插入n个c字符,n = 1时相当于就是插入单个字符,但不能没有n
//s3.insert(7, 'g'); //error:没有重载函数可以转换所有参数类型
s3.insert(7, 1, 'g');
cout << s3 << endl;
//iterator insert (iterator p, char c);
s3.insert(s3.begin(), ' ');
cout << s3 << endl;
//但是需要谨慎使用insert,因为insert需要将后面的字符挨个往后移动,时间复杂度为O(n^2)
}
int main()
{
Test_string4();
return 0;
}
讲解了前面的字符串创建(constructor),这里 erase 里面的形参意思大家应该也就清楚了。基于上面插入的结果我们对 erase 进行使用:
cpp
void Test_string4()
{
//删除数据
//string& erase (size_t pos = 0, size_t len = npos);
//iterator erase(iterator p); //迭代器用法
//头删数据
s3.erase(0, 1);
cout << s3 << endl;
s3.erase(s3.begin()); //迭代器用法
cout << s3 << endl;
//尾删数据
s3.erase(s3.size() - 1, 1);
cout << s3 << endl;
s3.erase(--s3.end()); //迭代器用法
cout << s3 << endl;
//删除多个数据
s3.erase(3, 5);
cout << s3 << endl;
s3.erase(3); //若不给第二个实参,则len默认给缺省值npos,即删除对应位置后面的全部数据
cout << s3 << endl << endl;
//和insert一样,头删erase也要谨慎使用,因为需要将后面所有数据挨个往前移动,时间复杂度为O(n^2)
}
int main()
{
Test_string4();
return 0;
}
1.3 字符串替换:replace() 修改指定位置内容
**replace()**能直接替换字符串中指定位置,指定长度的内容。可以替换为字符,字符串或者子串,有部分自己的使用场景。
cpp
void Test_string4()
{
//字符串替换:replace() 修改指定位置内容
string s4("Hello world");
s4.replace(5, 1, "&&&");//把下标为5这个位置的1个字符替换成&&&,由于是少的位置替换多的字符
//这就说明了需要利用前面insert的逻辑将后面的字符往后移动
cout << s4 << endl;
s4.replace(5, 3, "*");//把下标为5这个位置开始的三个字符替换成*,由于是多的位置替换少的字符
//这也就说明了需要利用前面erase的逻辑将后面的字符往前移动
//练习:将所有空格全部替换为&
//第一种方法:find()查找
string s5("Hello world a b c d");
size_t pos = s5.find(" ");
while (pos != string::npos) //当find没有找到对应匹配项,则返回npos,但是npos是类中成员,需要用类访问
{
s5.replace(pos, 1, "&");
//pos = s5.find(" "); //pos改为下一个空格的下标
pos = s5.find(" ", pos + 1); //优化:从 pos + 1 的位置开始找,不需要再从头开始找
}
cout << s5 << endl;
//但是我们会发现上面这种方法会比较麻烦,每次只能找一个空格替换成&
//所以我们考虑用另一个字符串来存放替换后的结果
//第二种方法:空间换时间
string s6("Hello world a b c d");
string tmp;
tmp.reserve(s6.size()); //预分配空间,防止后续多次扩容
for (auto ch : s6)
{
if (ch == ' ')
{
tmp += '&';
}
else
{
tmp += ch;
}
}
//s6 = tmp; //最后赋值给s5
//也可以使用string中的swap()
s6.swap(tmp);
cout << s6 << endl;
}
int main()
{
Test_string4();
return 0;
}

2、加餐补充:string常用场景的一些实用接口和技巧
除了前面讲的一些以外,其实我们的 string 还有很多比较实用的接口,这里就再给大家分享一部分,如果有没分享到的是因为使用的频率不高,但是大家需要使用的话可以自己查阅参考文档去了解一下用法。
2.1 字符串查找:find() 找字符/子串
find() 从指定位置从左往右找字符或者子串,返回第一次出现的下标;没有找到就返回 string :: npos(这个代表一个很大的数,表示"不存在")
cpp
void Test_string5()
{
//字符串查找:find() 找字符/子串
//找字符
string s1 = "hello world";
// 1. 找字符'w'
size_t pos1 = s1.find('w');
if (pos1 != string::npos)
{
cout << "'w'在位置:" << pos1 << endl;// 输出6
}
// 2. 找子串"world"
size_t pos2 = s1.find("world");
if (pos2 != string::npos)
{
cout << "world在位置:" << pos2 << endl;// 输出6
}
// 3. 从下标5开始找字符'o'
size_t pos3 = s1.find('o', 5); // 从下标为5的位置 ' ' 往后找
cout << "'o'在位置:" << pos3 << endl;// 输出7(s[7]是'o')
}
int main()
{
Test_string5();
return 0;
}

2.2 子串截取:substr() 从指定位置取指定长度

cpp
void Test_string5()
{
//子串截取:substr()从指定位置取指定长度
string s2 = "Hello world";
// 1. 从位置6开始,取5个字符
string sub1 = s2.substr(6, 5); // sub1 = "world"
cout << sub1 << endl;
// 2. 从位置2开始,取到末尾
string sub2 = s2.substr(2); // sub2 = "llo world"
cout << sub2 << endl;
}
int main()
{
Test_string5();
return 0;
}

2.3 C字符转换:c_str () 适配C语言库函数
我们在一些特殊的场景下需要使用C语言的 char* (比如 printf 输出),直接用 string 是不支持的,只能用 c_str () 把 string 转换成 const char*。

cpp
void Test_string5()
{
//C字符转换:c_str() 适配C语言库函数
string s3 = "Hello world";
//1. printf输出(printf不直接支持string)
//printf("%s\n", s3);//虽然是警告不是报错,但由于不支持string打印的结果也不是我们预期的
//warning C4477: "printf": 格式字符串"%s"需要类型"char *"的参数,但可变参数 1 拥有了类型 "std::string"
printf("%s\n", s3.c_str());
// 2. 调用C库函数strlen(需要包含<cstring>)
size_t len = strlen(s3.c_str());
cout << len << endl << endl;
}
int main()
{
Test_string5();
return 0;
}

2.4 整行输入:getline() 读取带空格的字符串
在平常的使用中,如果使用 cin>>string 或者 scanf 读取字符串时,当遇到空格就会停止,而如果空格后面仍有字符串也不会被读取到,而是存到缓冲区里。而 getline() 能读取一整行的内容,包括空格。不传第三个实参则默认回车结束,也可以自己指定终止符。

比如我们下面这个题就必须使用 getline ,直接用 cin 或者 scanf 都是不行的

cpp
void Test_string5()
{
//整行输入:getline() 读取带空格的字符串
//istream& getline (istream& is, string& str, char delim);
//不传第三个实参则默认回车结束,可以指定终止符
string s4;
//cin >> s4; //cin读取字符串时,当遇到空格就会停止
//如果空格后面仍有字符串也不会被读取到,而是存到缓冲区里
getline(cin, s4, '*');
}
int main()
{
Test_string5();
return 0;
}

结束语
到此,string 类的大部分实用接口的使用就讲解完了,在下篇文章我们将会对 string 类的底层原理进行模拟实现。希望这篇文章对大家学习C++能有所帮助!
C++参考文档:
https://legacy.cplusplus.com/reference/
https://zh.cppreference.com/w/cpp
https://en.cppreference.com/w/