纪念 229头像
关注
C++ string(三)封面图

C++ string(三)

在这里插入图片描述

༺ 个人主页 · 纪念229 ༻

🏠我的博客主页🏠

༒专栏目录:《数据结构》༒

༒专栏目录:《算法》༒

༒专栏目录:《C++》༒

༒专栏目录:《MySQL数据库》༒

༒专栏目录:《前端开发》༒

༒其它有趣的计算机知识༒

༺世上本没有路,走的人多了自然就有了༻


本篇文章讲述的是C++ string类的讲解,希望对你有所帮助

本篇文章是对C++ string(三)的补充



1.test_string7()

void test_string7()
{
	string s1("hello world");
	//	s1.push_back(' ');
	//	s1.append("hello bit");
	//	//append("字符串")成员函数在字符串末尾加一串字符串
	//	s1.append(10, 'x');
	////appen	d(个数,'字符')成员函数在字符串后面加10个字符
	//	//std空间里有string
	s1 += ' ';
	s1 += "hello world";
	//这里调用的是+=运算符重载可以看作是append两种调用的方式另外一种使用方式
	cout << s1 << endl;

	s1 = 'x';
	cout << s1 << endl;

	s1.assign(10, 'y');
	//将原来的字符串变为10个y
	cout << s1 << endl;


	//insert 谨慎使用,底层数据挪动,效率低下,O(N)
	string s2("hello world");
	s2.insert(0, "yyy");
	//insert(下标,"字符串")成员函数在指定下标字符前加上字符串
	cout << s2 << endl;

	s2.insert(0, 1, '!');
	//insert(下标,插入个数,'字符')这个是在下标指向的字符前加入几个字符
	cout << s2 << endl;

	s2.insert(s2.begin(), '!');
	//insert(迭代器,'字符')在指定迭代器的字符前加上一个字符
	cout << s2 << endl;

	//erase 谨慎使用,底层数据挪动,效率低下,O(N)
	string s3("hello world");
	s3.erase(5, 1);
	//erase(下标,删除个数)成员函数从某个下标开始删除几个字符

	s3.erase(5);
	//erase(下标)从第5个下标指向的字符开始包括自己后面的字符全删
	cout << s3 << endl;

	//replace 谨慎使用,底层数据挪动,效率低下, O(N)
	string s4("hello world");
	cout << s4 << endl;
	s4.replace(5, 3, "#");
	//成员函数replace(下标,替换几个字符,替换的字符串)从指向下标的字符开始包括他自己替换几个字符为字符串
	cout << s4 << endl;

	s4.replace(5, 1, "!!!!!!!!!");
	cout << s4 << endl;


	//所有空格替换为%%
	string s5("          hello world hello bit");
	size_t pos = s5.find(' ');
	//find(字符) 成员函数从左到右查找字符串中的字符找到了返回该字符的下标没找到返回特殊值(表示未找到)
	while (pos != string::npos)
		//string::npos是一个静态常量表示未找到
	{
		s5.replace(pos, 1, "%%");
		pos = s5.find(' ', pos + 2);
		//find(要找的字符, 规定开始查找的下标(从这开始包括自己从左往右找目标字符))从指定下标找字符找到了返回该下标没找到返回静态常量(未找到)
	}
	//利用whlie(!)静态常量(含义未找到)对某要替换的字符进行替换
	cout << s5 << endl;


	string s6;
	//string是std里的成员函数自己有构造函数(不是默认构造字符串全为空)
	//如果是自定义类的成员变量有内置类型就是随机值有类它会调用它自己的构造函数(可以是默认构造,也可以是对应的构造函数否则会报错)string作为std类中的类它就是有自己对应的构造函数(字符串为空)
	s6.reserve(s5.size());
	for (auto ch : s5)
	{
		if (ch == ' ')
			s6 += "%%";
		else
			s6 += ch;
	}
	cout << s6 << endl;
}

s1 += ' ';
因为s1是string的类所以+=调用的是运算符重载意思是将右边的字符/字符串补到最后一个字符后面

s1 = 'x';这个s1是类对象 = 就是赋值重载作用是将原来的字符串变为左边的数据(意思是重载完后s1字符数组里就只剩右边的数据)

s1.assign(10, 'y');
string类里的assign(个数,字符)作用这里是将对象里的数据设置为只有10个’y’

s2.insert(0, "yyy");
string类里的insert(下标,字符串/字符)作用是在某下标位置上插入字符串/字符(时间复杂度为o(n)因为要移动下表以及下标后指向的数据)

s2.insert(0, 1, '!');
insert(下标,个数,字符)作用在下标指向的位子插入几个字符

s2.insert(s2.begin(), '!');
insert(迭代器,字符)作用:在指向的的位置插入一个字符

s3.erase(5);
string类erase(下标)作用从下标指向的数据开始到数据未都要删除

s4.replace(5, 3, "#");
s4.replace(5, 1, "!!!!!!!!!");

string类里的replace函数(下标, 替换几个字符,替换为哪个字符串)意思是从某下标开始替换几个字符为字符串

//所有空格替换为%%
string s5("          hello world hello bit");
size_t pos = s5.find(' ');
//find(字符) 成员函数从左到右查找字符串中的字符找到了返回该字符的下标没找到返回特殊值(表示未找到)
while (pos != string::npos)
	//string::npos是一个静态常量表示未找到
{
	s5.replace(pos, 1, "%%");
	pos = s5.find(' ', pos + 2);
	//find(要找的字符, 规定开始查找的下标(从这开始包括自己从左往右找目标字符))从指定下标找字符找到了返回该下标没找到返回静态常量(未找到)
}

这里的作用就是将字符串的前导空格字符替换为"%%“我们先用find找
’ ‘找到了((pos != string::npos))就进入循环将该下标上的’ '替换为”%%"更新pos从pos + 2开始找原因是要越过%%继续找前导’ '没有了循环结束

string::npos
这个nops是string域里定义的静态常量(没找到)
没找到 +=就是找到了

C++标准库里的string默认构造就是将对象设为空啥也没有(vector、list也是size为0capacity为0数据为空)

我们自己设计的类对象调用默认构造成员变量若只有内置类型就全是随机值有指针类型要申请空间类类型成员变量要设计合理(成员变量有指针要申请空间)

string s6;
//string是std里的成员函数自己有构造函数(不是默认构造字符串全为空)
//如果是自定义类的成员变量有内置类型就是随机值有类它会调用它自己的构造函数(可以是默认构造,也可以是对应的构造函数否则会报错)string作为std类中的类它就是有自己对应的构造函数(字符串为空)
s6.reserve(s5.size());
for (auto ch : s5)
{
	if (ch == ' ')
		s6 += "%%";
	else
		s6 += ch;
}
cout << s6 << endl;

这个是一种拷贝的写法


2.test_string8()

void test_string8()
{
	string filename("test.cpp");
	FILE* fout = fopen(filename.c_str(), "r");
	//这里是只写了个文件名字符串不是绝对路径那么它就会默认找的是当前运行目录没找到就返回空(不会去其它目录找)
	//FILE这个叫文件流结构体文件流指向它(结构体C语言标准库)
	//fopen(打开文件)返回的就是文件流
	//fopen(要找的目录(字符串),"r/w")//r(只读)w(只写)
	//fopen会从此文件开始找这个字符串(文件名)找到了返回文件流没找到返回空
	//fopen属于C语言标准库第一个参数的字符串要用C语言格式的字符串所以要用.c_str()将C++格式的字符串变成c语言格式的字符串返回C语言格式的字符串
	if (fout == nullptr)//c++里用nullptr比NULL(返回类型为整数0)更好
	{
		cout << "fopen error" << endl;
		return;
	}

	char ch = fgetc(fout);
	//文件流(地址)
	//fgetc(文件流)读取文件流结构里的字符指向下一个字符并返回该字符的sacll码值用char接收得到的还是该字符读取失败返回EOF
	while (ch != EOF)
	{
		cout << ch;
		ch = fgetc(fout);
	}
	//这里打印循环结束不是因为打印结束是因为接收的是char类型被ascll码值为255赋值了返回-1(EOF)打印结束
	//连续读取文件数据
}




FILE* fout = fopen(filename.c_str(), "r");
这里FILE是文件流(指针)
fopen(char
a, 特定字符串)这里字符串返回的就是char*类型第二个参数是"r"只读,"w"只写等(第一个参数就写一个文件名的话它就会从当前工作目录查找文件找不到就返回EOF这里的终端(windows)读字符不分大小写)

string类里的c_str()函数作用是将C++风格的字符串变为C语言风格的字符串返回一个char*类型fopen第一个形参只支持C语言类型的字符串

char ch = fgetc(fout);
//文件流(地址)
//fgetc(文件流)读取文件流结构里的字符指向下一个字符并返回该字符的sacll码值用char接收得到的还是该字符读取失败返回EOF

while (ch != EOF)
{
	cout << ch;
	ch = fgetc(fout);
}

注意我这里写的自定义函数test_stirngX()都在头文件Test.cpp里面

char ch = fgetc(fout);
这里fgetc(文件流类型变量)从该文件里读取一个字符再往后挪一位下一次调用这个函数就从此位子开始

while (ch != EOF)
{
	cout << ch;
	ch = fgetc(fout);
}

这里是连续读取字符串打印

这里只读一部分该文件的原因是读到sacll码值为255的字符赋值给了ch变为-1(EOF)循环结束


3.findsuffix与split_url

一下讲解的代码将引用于test_string9(),下一篇文章我会讲

string findsuffix(const string& filename)
{
	size_t i = filename.rfind('.');
	//rfind(字符)从字符串尾开始找字符返回该字符下标
	if (i != string::npos)
	{
		return filename.substr(i);
		//cout << filename.substr(i);//这里是返回不是打印
		//substr(下标)返回下标指向的字符以及字符后面的有效字符
		//substr并不是将对象真的裁剪只是将要裁剪的部分返回
	}
	else
	{
		/*string empty;
		return empty;
		return string();*/
		return "";//""既可以装字符也可以装字符串
	}
}

//void split_url(const string& url)
//{
//	size_t i1 = url.find(':');
//	if (i1 != string::npos)
//	{
//		cout << url.substr(0, i1) << endl;
//	//substr(下表从哪开始,裁剪个数)这里裁剪的是下标为0以及下标i1 - 1之间的的字符串包括它们自己
//	}
//	
//	size_t i2 = i1 + 3;
//	//下标加几指的就是该数据之后的第几个位子(这里要越过//所以要到该字符第3个位置所以加3)
//	size_t i3 = url.find('/', i2);
//	if (i3 != string::npos)
//	{
//		cout << url.substr(i2, i3 - i2) << endl;//substr的第二个参数指的是要裁剪的个数(这里是i3 - i2(从i2开始截取的个数))
//		cout << url.substr(i3 + 1) << endl;
//		//下标和个数要分清
//	}
//	cout << endl;
//}

vector<string> split_url(const string& url)
//返回类型就是类(vector)
{
	vector<string> v;

	size_t i1 = url.find(':');
	if (i1 != string::npos)
	{
		v.push_back(url.substr(0, i1));
		//这里的v是vector<string>类型的字符数组它的push_back()和insert都可以插入字符串string类型insert()可以插入字符串push_back只能插入字符

	}

	size_t i2 = i1 + 3;
	size_t i3 = url.find('/', i2);
	if (i3 != string::npos)
	{
		v.push_back(url.substr(i2, i3 - i2));//i3 - i2截取的就是i2读过的个数
		//v.push_back(url.substr(i2, i3);//i3 - i2截取的就是i2读过的个数只写个i3不对
		v.push_back(url.substr(i3 + 1));
	}

	return v;
}
string findsuffix(const string& filename)
{
	size_t i = filename.rfind('.');
	//rfind(字符)从字符串尾开始找字符返回该字符下标
	if (i != string::npos)
	{
		return filename.substr(i);
		//cout << filename.substr(i);//这里是返回不是打印
		//substr(下标)返回下标指向的字符以及字符后面的有效字符
		//substr并不是将对象真的裁剪只是将要裁剪的部分返回
	}
	else
	{
		/*string empty;
		return empty;
		return string();*/
		return "";//""既可以装字符也可以装字符串
	}
}

这个代码的含义就是找后缀(.)

size_t i = filename.rfind('.');
这里string类里的rfind(‘.’)意思是从最后一个字符开始找起从右往左找字符’.'找到了返回改为值得下标

return filename.substr(i);
string类里的substr(下标)从该下标开始到字符串末的字符截取返回(该截取不是正真的截断对象数据不改变)没找到就返回’ ’

vector<string> split_url(const string& url)
//返回类型就是类(vector)
{
	vector<string> v;

	size_t i1 = url.find(':');
	if (i1 != string::npos)
	{
		v.push_back(url.substr(0, i1));
		//这里的v是vector<string>类型的字符数组它的push_back()和insert都可以插入字符串string类型insert()可以插入字符串push_back只能插入字符

	}

	size_t i2 = i1 + 3;
	size_t i3 = url.find('/', i2);
	if (i3 != string::npos)
	{
		v.push_back(url.substr(i2, i3 - i2));//i3 - i2截取的就是i2读过的个数
		//v.push_back(url.substr(i2, i3);//i3 - i2截取的就是i2读过的个数只写个i3不对
		v.push_back(url.substr(i3 + 1));
	}

	return v;
}

vector<string> split_url(const string& url)

这里的vector是一种类模板含义是某种类型的数组(这里是string类型的数组每个元素都是一个string类)

这里是自定义的函数返回类型是vector
代码含义是将传入的地址字符串分离


文章到此就告一段落,希望对你有所帮助,感谢观看!

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2503_94479566/article/details/167492335

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--