string和string_view用法指南

1、C风格字符串和C++字符串区别

我们编写的每个应用程序都会使用某种类型的字符串,使用C语言时,没有太多选择,只能使用普通的以’\0’结尾的字符数组表示的字符串这种表达方式会导致许多问题,例如会导致安全漏洞的缓冲区溢出,C++标准库包含一个安全易用的std::string类,这个类符合RALL思想,没有这些缺点

2、C++std::string类

C++提供了一个得到极大改善的字符串概念,并作为标准库的一部分提供了这个字符串的实现。在C++中,std::string是一个类(实际上是basic_string模板类的一个实例),这个类支持< cstring >中提供的许多功能,还能自动管理内存分配

2.1、使用std::string类

C++的string类使用起来比C风格字符串更容易,以为它内部封装了许多运算符重载,如下是测试代码:

#include<iostream>
#include<string>


int main()
{
	std::string str1 = "hello";
	std::string str2 = " world";
	auto str3 = str1 + str2;
	std::cout << str3 << std::endl;
	return 0;
}

2.2、字符串比较

在C++的string类中,操作符(==、!=、<、>等)都被重载了,这些运算符可以操作真正的字符串的字符,单独的字符可以通过方括号运算符[]访问。
C++string类另外提供了一个compare()方法,它的行为类似于C语言的strcmp()具有类似的返回类型,下面是测试代码:

#include<iostream>
#include<string>


int main()
{
	std::string a = "12";
	std::string b = "34";
	auto ret = a.compare(b);
	if (ret < 0)
	{
		std::cout << "a<b" << std::endl;
	}
	else if (ret > 0)
	{
		std::cout << "a>b" << std::endl;
	}
	else if (ret == 0)
	{
		std::cout << "a==b" << std::endl;
	}
	return 0;
}

测试代码的结果:
在这里插入图片描述

2.3、字符串与数字相互转化

很多情况下我们输出某条包含数字的语句时都需要将数字转化为字符串才可以将语句输出,如下是std标准库中封装的数字转化为字符串接口:

string to_string (int val);
string to_string (long val);
string to_string (long long val);
string to_string (unsigned val);
string to_string (unsigned long val);
string to_string (unsigned long long val);
string to_string (float val);
string to_string (double val);
string to_string (long double val);

下面是std::to_string的接口的案例:

#include<iostream>
#include<string>

int main()
{
	int num = 42;
	auto str = std::string("I have ") + std::to_string(42) + std::string("yuan");
	std::cout << str << std::endl;

	return 0;
}

上面讲了数字转化为字符串,如下是字符串转化为数字的接口:
在这里插入图片描述
在这里插入图片描述
接下来是字符串转化为数字的案例:

#include<iostream>
#include<string>

int main()
{
	//字符串转化为整数
	std::string str1 = "42";
	auto num = std::stoi(str1);
	std::cout << num << std::endl;

	//字符串转化为浮点型
	std::string str2 = "3.14";
	auto dot = std::stof(str2);
	std::cout << str2 << std::endl;

	return 0;
}

注意:std::stoi/stof/stod/stoll等,它们的第二个参数是size_t类型的pos指的是非数字部分的位置,用于将非数字部分过滤掉,第三个参数是int 类型的base用于进行进制的转化,它默认是十进制

2.4、字符串的截取操作

std::string提供了一个截取字符串的接口,它会截取从pos位置开始,长度为len的子字符串,原字符串不会发生改变,它的原型如下:

string substr(size_t pos=0,size_t len=-1)const

如果原字符串剩余部分长度不足len,则返回长度小于len的子字符串而不会出错。如果pos超出原字符串的范围,则会抛出std::out_of_range的异常,如下是字符串截取的案例:

#include<iostream>
#include<string>

int main()
{
	std::string str = "helloSakura";
	std::cout << "从第2个字符开始截取长度为4的字符串:" << str.substr(2, 4) << std::endl;
	std::cout << "从第2个字符开始截取长度为99的字符串:" << str.substr(2, 99) << std::endl;
	std::cout << "从第2个字符开始截取到末尾的字符串:" << str.substr(2) << std::endl;
	std::cout << "从头开始截取长度为5的字符串:" << str.substr(0, 5) << std::endl;
	//throw out_of_range
	//std::cout << "从第100个字符开始截取长度为5的字符串:" << str.substr(100, 5) << std::endl;
	return 0;
}

测试代码的运行结果:
在这里插入图片描述

2.5、字符串的查找

当我们要查找某一个字符串的子串时,可以通过string类中的find()方法查找,如下是find()方法的原型:
在这里插入图片描述

find(str,pos):如果找到了给定的子串,则返回它的位置;如果没有找到,则返回string::npos,如果给定了pos位置,则会从pos位置开始查找给定str,而不是从最开始位置查找str

如下是find()的寻找子字符的测试例子:

#include<iostream>
#include<string>

int main()
{
	std::string str = "helloSakura";
	std::cout << "查找h字符的结果:" << str.find('h') << std::endl;
	std::cout << "查找e字符的结果:" << str.find('e') << std::endl;
	std::cout << "查找l字符的结果:" << str.find('l') << std::endl;
	std::cout << "查找o字符的结果:" << str.find('o') << std::endl;
	std::cout << "查找a字符的结果:" << str.find('a',2) << std::endl;
	return 0;
}

测试代码的结果:
在这里插入图片描述
如下是find()的应用案例:计算子字符串出现次数

#include<iostream>
#include<string>

size_t stringCount(const std::string& str, const std::string& sub)
{
	size_t num=0, pos = 0;
	while (true)
	{
		pos = str.find(sub, pos);
		if (pos == str.npos)
		{
			break;
		}
		num++;
		pos += sub.size();
	}
	return num;
}

int main()
{
	std::cout << stringCount("hellolldsdsallwds", "ll") << std::endl;
	return 0;
}

测试代码的结果:
在这里插入图片描述

2.6、寻找集合内的任意字符

find_first_of是string类中查找在字符串中第一个与指定字符串中的某个字符匹配的字符,返回它的位置。它的原型如下:
在这里插入图片描述
寻找字符串集合内的任意字符的测试代码:

#include<iostream>
#include<string>

int main()
{
	std::string str = "helloSakura!!";
	auto it = str.find_first_of("lSa");
	std::cout << it << std::endl;
	return 0;
}

测试代码的结果:
在这里插入图片描述

2.7、替换子字符串

replace()是string类中用来替换一段子字符串的接口,它的原型为:
在这里插入图片描述

如下是replace()的代码测试:

#include<iostream>
#include<string>

int main()
{
	std::string str = "make Sakura happy";
	str.replace(5, 6, "Naruto");
	std::cout << str << std::endl;
	return 0;
}

测试代码的结果:
在这里插入图片描述
下面使用replace()批量替换字符串案例:

#include<iostream>
#include<string>

void replace_allStr(std::string& str, const std::string& from, const std::string& to)
{
	size_t pos = 0;
	while (true)
	{
		pos = str.find(from, pos);
		if (pos == str.npos)
			break;
		
		str.replace(pos, from.size(), to);
		pos += from.size();
	}
}

int main()
{
	std::string str = "hello Sakura,and good luck for Sakura!!";
	replace_allStr(str, "Sakura", "Naruto");
	std::cout << str << std::endl;

	return 0;
}

测试代码的结果:
在这里插入图片描述

3、std::string_view

在C++17之前,为接收只读字符串的函数选择形参类型一直是一件进退两难的事情。若使用std::string,则必须调用c_str()或则data()来获取const char*。更糟糕的是,函数将失去std::string良好的面向对象的方面和良好的API。

在C++17中,通过引入std::string_view类解决了所有问题,std::string_view类是std::basic_string_view类模板的实例化。string_view基本就是const string&的简单替代品,但不会产生开销。它不复制字符串,string_view支持与std::string类似的接口。一个例外是string_view缺少c_str()的接口,但data()可用。另外string_view添加了remove_prefix(size_t)和remove_suffix(size_t)方法,前者将起始指针前移给定的偏移量来收缩字符串,后者则是将结尾指针倒退给定的偏移量来收缩字符串

如下是string_view简单的使用案例:

#include<iostream>
#include<string>
#include<string_view>

int main()
{
	std::string str1 = "hello";
	//深拷贝
	std::string str2 = str1;
	//弱引用
	std::string_view sv1 = str1;
	//浅拷贝
	std::string_view sv2 = sv1;
	//打印未修改的测试结果
	std::cout << "str1:" << str1 << std::endl;
	std::cout << "str2:" << str2 << std::endl;
	std::cout << "sv1:" << sv1 << std::endl;
	std::cout << "sv2:" << sv2 << std::endl;
	//分隔符
	std::cout << "-----------------------------------------" << std::endl;
	//修改str1的第一个字符
	str1[0] = 'H';
	//打印修改后的结果
	std::cout << "str1:" << str1 << std::endl;
	std::cout << "str2:" << str2 << std::endl;
	std::cout << "sv1:" << sv1 << std::endl;
	std::cout << "sv2:" << sv2 << std::endl;
	return 0;
}

测试代码的结果:
在这里插入图片描述

注意:str2是对str1的深拷贝,因为调用了std::string的拷贝构造函数,所以str1被修改时,str2仍然不变。sv1和sv2都是指向str1的弱引用,所以str1被修改时,sv1和sv2都被改变

3.1、string_view和string的运算符操作

当我们将string_view类型的常量弱引用类型的字符串和string类型的字符串进行相加(运算符+)操作时会出错,必须要先将string_view转化为const char*,也就是调用data()接口,测试代码如下:

#include<iostream>
#include<string>
#include<string_view>

int main()
{
	std::string str1 = "hello";
	std::string_view sv1 = " world";
	//使用+号运算符时,必须将string_view转化为const char*
	auto it = str1 + sv1.data();
	//使用append追加字符串不会出错
	auto it2 = str1.append(sv1);
	std::cout << it2 << std::endl;

	return 0;
}

3.2、string_view的字符串收缩

之前讲到了string_view除了可以使用string中的接口以外,自身也添加了两个新的接口,remove_prefix()和remove_suffix(),这两个接口用于实现字符串的收缩,下面是简单的使用这两个接口的案例:

#include<iostream>
#include<string>
#include<string_view>

int main()
{
	std::string str1 = "hello Sakura";
	std::string_view sv1 = str1;
	//从前向后收缩1个字符
	sv1.remove_prefix(1);
	std::cout << "sv1:" << sv1 << std::endl;
	//从后向前收缩一个字符
	sv1.remove_suffix(1);
	std::cout << "sv1:" << sv1 << std::endl;
	return 0;
}

测试代码的结果:
在这里插入图片描述

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: string是一个标准库中的字符串类型,它使用动态分配的字符数组来存储字符串。而string_viewC++17中引入的类型,它是对现有字符串的一种非独占、只读视图,不对其进行拷贝或分配,因此可以避免不必要的内存分配和字符串复制。string_view适合用于字符串查找、函数参数以及算法实现等场景。 ### 回答2: string_viewstringC++标准库中用于处理字符串的两个不同的类。 string是一个动态数组,存储了一个字符序列,并提供了一系列成员函数和操作符用于对字符序列进行操作。它是一个可变长度的字符串,可以通过改变字符串的长度来改变字符串的内容。使用string需要进行内存分配和释放的操作,因此在频繁操作字符串的场景下可能会带来性能的开销。 而string_view是一个轻量级的只读字符串类,它不负责内存的管理,它只是一个字符序列的非拥有者,类似于C语言中的指针。它提供了一个只读的视图,允许我们以只读方式访问底层的字符序列,而不需要复制或者分配新的内存。string_view可以用于有效地传递字符串参数,而无需拷贝整个字符串。另外,string_view还提供了一些常用的成员函数来方便地操作字符串。 总的来说,string_view主要适用于那些只需要对字符串进行读取操作而不需要修改的场景,例如字符串的搜索、比较、输出等。而string适用于需要频繁修改字符串内容的场景。string_view基本不需要进行内存分配和释放,因此在性能和内存占用上可能会比string更加高效。但需要注意的是,由于string_view没有自己的内存管理能力,所以需要确保底层字符串的生命周期要比string_view更长,否则会出现未定义行为。 综上所述,string_viewstring是两种不同的字符串类,各自适用于不同的场景,可以根据具体需求选择使用。 ### 回答3: string_viewstring 都是C++标准库中的字符串类型,但它们有一些重要的区别。 首先,string 是一个可变的字符串类型,而 string_view 是一个只读的字符串类型。这意味着,string_view 可以用于引用字符串的片段,而不需要额外的内存分配和复制。而 string 则提供了更多的字符串操作函数,例如插入、删除、替换等。所以,如果我们需要在字符串上执行修改操作,那么使用 string 会更合适;而如果只需要读取字符串或者对不可变的字符串做一些操作,那么使用 string_view 更加高效。 其次,string 是一个完整的字符串对象,它在内存中存储了字符序列,并且具有自动内存管理。而 string_view 则是一个对字符串的引用,并没有自己的内存管理功能。string_view 只是一个轻量级的字符序列包装器,它包含了指向字符序列的指针和长度信息。这使得 string_view 能够更有效地处理大量的字符串操作。 再次,string_view 可以用于代替 const char* 或 const char[],并且具有更好的可读性。它可以接受各种不同类型的字符串作为输入,包括字符串字面量、char*、std::string 等等,这样我们可以更方便地在这些不同的字符串类型之间进行转换。 总之,string_view 是一个只读的字符串引用,适用于对字符串的读取和不可变的操作,具有高效的性能和更好的可读性。而 string 则是一个完整的可变字符串对象,适用于需要修改字符串内容的场合。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值