作者:@小萌新
专栏:@初阶C++
作者简介:大二学生 希望能和大家一起进步
本篇博客简介:介绍下String类的一部分用法
想不出来啥鸡汤了 学吧~
C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函
数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。
oop思想: 指的是面向对象编程
C++中对于string的定义为:typedef basic_string string; 也就是说C++中的string类是一个泛型类,由模板而实例化的一个标准类,本质上不是一个标准数据类型。
至于我们为什么不直接用String标准数据类型而用类是因为一个叫做编码的东西
我们每个国家的语言不同 比如说英语使用26个英文字母基本就能表述所有的单词 但是对于中文的字符呢?是不是就要用其他编码方式啊(比如说utf-8)
常用函数如下
我们会讲解大部分重要的函数
我们这里有两种访问方式
使用operator[]实现数组下标式的访问
但是在这之前 我们首先来看看这一段代码
string s1("hello world");
cout << s1.size() << endl;
这里第一行代码的意思是初始化构造一个string类 初始化赋值为 hello world
s1.size()是表示的s1字符串的大小(这里使用s1.length())
之后我们开始使用下标进行访问 代码表示如下
string s1("hello world");
//cout << s1.size() << endl; // s1.length()
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << ' ';
}
这里其实等价于这一行代码
cout << s.operator[](i) << " ";
函数重载嘛
代码表示如下
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1.at(i) << ' ';
}
运行结果如下
唯一的区别就是报错的时候
下标访问报断言错误
at访问报异常
老规矩 我们先来看迭代器的语法
string::iterator it = s.begin();
我们首先写个String类名 后面跟上iterator(迭代器) 再后面加上一个it
等于号的右边写上对象的begin() 或者 end()
我们目前将它当作指针来看待 目前这个阶段这样子理解就好
使用方式如下
string s("hello world");
string::iterator it = s.begin();
while (it != s.end())
{
cout << *it;
it++;
}
当然我们也可以来修改迭代器里面的内容
我们先来看语法格式
string::reverse_iterator it = s.rbegin();
我们这里可以看到 其实变化的就是一个 reverse 还有最后的rbegin()
代码表示如下
string s("hello world");
string::reverse_iterator it = s.rbegin();
while (it != s.rend())
{
cout << *it;
it++;
}
我们发现 这里是不是代码有很多啊 那么我们练习到之前的知识 是不是就能想起来一个auto关键字
那么我们试试行不行
所以这里是不是更能明确一点了 知识之间不是相互孤立的
相比于迭代器 其实这里的改变就是不能写了 只能读(权限缩小)
代码表示如下
int main()
{
const string s("hello world");
string::const_iterator it = s.begin();
while (it != s.end())
{
cout << *it;
it++;
}
return 0;
}
这里肯定就不能修改啦 不然肯定会报错的
和正向迭代器一样 这里就不多解释了
代码跟运行图如下
int main()
{
const string s("hello world");
string::const_reverse_iterator it = s.rbegin();
while (it != s.rend())
{
cout << *it;
it++;
}
return 0;
}
这个我们也是在之前的auto语法里面讲过了 代码表示如下
string s("hello world");
for (auto x : s)
{
cout << x << ' ';
}
那么我们想要修改呢?
是不是也讲过 直接使用他们的引用就可以了(不引用肯定是不可以的 因为这里只是一个简单的赋值)
构造函数几种重要的格式如下
这里只讲解三个重点构造函数
代码表示如下
string s;
我们debug来看看是什么效果
这里就是一个空字符串了
和无参构造差不多 代码表示如下
string s("hello world");
还是一样debug看看
这里可以发现 字符串的大小(size)变成了11 然后字符串里面的内容变成了 hello world
代码表示如下
string s("hello world");
string s1(s);
还是一样 debug看看
s1也变成了hello world捏
还是一样捏 咱们挑重点的介绍
首先还是一样 上代码
cout << s.size();
我们输出之后可以发现大小是11
这里是不是有点眼熟 我们debug看到的size是不是也是11啊 所以说这里就是将debug的值返回而已
这个也很简单 判断是否为空的
比如说我们创建两个字符串 一个为空 一个不为空试试看
这里表示的很清楚了
这里的clear函数可以和empty联动一下
我们发现清除之后两个字符串就变成全空了
这个函数用于预先开空间 因为每当字符串长度大于容量的时候都会扩容
所以如果我们知道我们需要的空间是多少我们就可以使用这个函数了
我们可以发现 这里的空间变成了1007 (因为是按照1.5倍开空间的)
我们这里使用resize可以改变size的大小 假如说我们size的大小大于字符串的size 后面就会以‘\0’结尾
假如我们resize的大小小于原来的大小 后面的字符就会截断
这里比较重要的其实就是一个+=
这里演示下
我们可以发现 后面确实连接上了一个字符串
这个接口函数的用法也很简单 有三个参数 分别是要替换的位置 删除的数据大小 替换的数据
#include
#include
#include
int main()
{
string s1 = "The sixth sick sheik's sixth sheep's sick";
string key = "sixth";
int findpos = s1.find(key);
while (findpos!=string::npos)
{
s1.replace(findpos,key.size(),"seventh");
findpos = s1.find(key);
}
cout << s1 << endl;
return 0;
}
这里其实也不太常用
我们记住几个用法 有印象就可以
string str = "hello world";
string str2 = "hard ";
string str3 = "it is so happy wow";
//s.insert(pos,n,ch) 在字符串s的pos位置上面插入n个字符ch
str.insert(6,4,'z'); // str = "hello zzzzworld"
//s.insert(pos,str) 在字符串s的pos位置插入字符串str
str.insert(6,str2); // str = "hello hard world"
//s.insert(pos,str,a,n) 在字符串s的pos位置插入字符串str中位置a到后面的n个字符
str.insert(6,str3,6,9); // str = "hello so happy world"
//s.insert(pos,cstr,n) 在字符串s的pos位置插入字符数组cstr从开始到后面的n个字符
str.insert(6,"it is so happy wow",6); // str = "hello it is world"
这里我们可以将这个操作符理解成 清空赋值 现在这三种赋值方式我们是不是也是轻车熟路了
int main()
{
string s1 = "hello world";
string s2 = "welcome to my world";
s1.assign("hello");
cout << s1 << endl;
s1.assign(s2);
cout << s1 << endl;
s1.assign(s2, 5, 5); // s2第五个位置 往后五个字符
cout << s1 << endl;
return 0;
}
它同样也有三种使用方式 (删除)
int main()
{
string s1 = "hello world";
string s2 = "welcome to my world";
s1.erase(); // 这里是全部删除
cout << s1 << endl;
s1 = "hello world";
s1.erase(0, 3); // 删除0~3
cout << s1 << endl;
s1 = "hello world";
s1.erase(3); // 删除3~后面全部
cout << s1 << endl;
return 0;
}
我们这里可以将整个字符串反转
我们使用这个函数的时候返回的是一个字符串
我们可以发现 这里两个的类型明显不同
一个是string对象
一个是字符指针(也就是字符串)
这里find有四种用法
第一种 也是最常用的
string str = "The apple thinks apple is delicious"; //长度34
string key = "apple";
//s.find(str) 查找字符串str在当前字符串s中第一次出现的位置
int pos1 = str.find(key); // 4
我们这里可以发现 apple是在第四个位置出现的 所以说这里pos1会是4
假如说我们要查找的是以一个字符‘a’ 那么它返回的值也会是4
那么如果说 我们要查找的是一个不存在的字符呢?
我们可以看到这里的pos5变成了26 实际上也就是字符串最后的值
那么假设我们要找从某位置到某位置的值呢?
只要在后面加上个范围就好
第二个这个是什么意思呢?
就是让我们从第五个位置开始 找key值 并且返回它的下标
那么我们来看看最后一个 其实唯一的区别就是查找变成字符了
我们这里查找一个字符使用的是这个pos4 后面的数字表示从多少位置开始查找
这里是一种不常用的用法
int main()
{
string s1 = "The apple thinks apple is delicious";
int pos1 = s1.find("thi0ng", 0,4 );
cout << pos1 << endl;
return 0;
}
查找前面这个字符串 从0这个位置开始 查找这个字符串的4个字符
这个的用法也很简单
得到pos位置后面n个字符组成的字符串
得到一整行的字符串
使用格式如下
getline(cin , s);
https://legacy.cplusplus.com/reference/string/string/find/
现在给我们这样子的一串字符串
要求我们查找三部分的内容
1 前面的https
2 查找域名
3 查找地址
首先我们来看前面的https
我们来看看 是不是只要找到冒号就能找到前面的协议啊
这样子是不是很简单就找到了
然后我们开始查找域名 观察下这个地址 是不是pos+3的位置往后面找 找到第一个‘/’ 这中间就是域名啊
写出这样子的代码就能够找到域名了
接着我们来找找后面的内容
这个时候直接从pos2查找到最后就可以了
替换空格
这个题目其实我们以前用双指针的做法做过
但是我们现在学了string类 是不是能很简单的解决它啦
代码表示如下
class Solution {
public:
string replaceSpace(string s)
{
// 首先查找空格的位置
int pos = s.find(' ');
// 之后我们开始替换
while(pos != string::npos)
{
s.replace(pos,1,"%20");
pos = s.find(' ');
}
return s;
}
};
我们来看看效果
可以完美运行
题目要求如下
代码表示如下
int main()
{
string s;
getline(cin,s); // 输入一行的字符串
int pos = s.rfind(' ');
string s2 = s.substr(pos+1);
cout<<s2.size()<<endl;
return 0;
}
经过了这几题是不是发现使用string类刷题特别方便啊
这就是我们为什么学习STL的原因
本篇博客介绍了String类的基本使用方法以及使用String类刷一些题目
由于作者水平有限 错误在所难免 出现了错误希望大佬能够及时指正啊
如果这篇文章帮助到你别忘了一键三连啊
阿尼亚 哇酷哇酷!