C++ string 类使用超全攻略(下):修改、查找、获取及常见实用接口深度解析

🔥小叶-duck个人主页

❄️个人专栏《Data-Structure-Learning》

《C++入门到进阶&自我学习过程记录》

未择之路,不须回头
已择之路,纵是荆棘遍野,亦作花海遨游


目录

前言

[一、string 类0基础上手:常见核心接口使用(附实操代码及注释)](#一、string 类0基础上手:常见核心接口使用(附实操代码及注释))

1、字符串修改:高频操作(拼接/插入/删除/清空)

[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、加餐补充:string常用场景的一些实用接口和技巧

[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/

相关推荐
程序员老舅2 小时前
【无标题】
c++·嵌入式·八股文·c++八股文·八股文面试题·c++面经·c++面试题
Tao____2 小时前
可以本地部署的物联网平台
java·开发语言·物联网·mqtt·低代码
码界奇点2 小时前
基于DDD与CQRS的Java企业级应用框架设计与实现
java·开发语言·c++·毕业设计·源代码管理
柏林以东_2 小时前
线程安全的数据集合
java·开发语言·安全
Frank_refuel2 小时前
C++STL之set和map的接口使用介绍
数据库·c++·算法
喵喵喵小鱼2 小时前
arcgis JavaScript api实现同时展示多个撒点气泡
开发语言·javascript·arcgis
闻缺陷则喜何志丹2 小时前
【模拟】P9670 [ICPC 2022 Jinan R] Frozen Scoreboard|普及+
c++·算法·模拟·洛谷
fengfuyao9852 小时前
基于MATLAB的螺旋锥齿轮齿面接触分析(TCA)实现
开发语言·matlab
王老师青少年编程2 小时前
2024年6月GESP真题及题解(C++八级): 最远点对
c++·题解·真题·gesp·csp·八级·最远点对