string类模板
string类模板
介绍
1. string是表示字符串的字符串类
2.该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
string类的常用接口说明
常见构造
选定位置拷贝
void Teststring()
{
string s1; // 构造空的string类对象s1
string s2("hello bit"); // 用C格式字符串构造string类对象s2
string s3(s2); // 拷贝构造s3
string s6 = "hello bit"; //隐式类型转换
string s4(s2,3,5);// 从3的位置开始,拷贝5个字节长度。
string s5(s2,3); //不写长度默认拷贝到全部长度,即-1的位置
}
迭代器
iterator类似于string的内部类,所以要string::
cosnt修饰的是iterator指向的内容,迭代器本身可以移动
类似这个样子。*p2不能修改但是p2可以修改;p3不能修改。
begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
int main()
{
string s1("hello world");
string::iterator it1 = s1.begin();
for (auto e : s1)
{
cout << e << "";
}
cout <<s1<< endl;
while (it1 != s1.end())
{
cout << *it1 << " ";
++it1;
}
cout << endl;
}
这里在熟练知道后,string::iterator可以用auto来代替
反向遍历
这里要和正向遍历反一下,++就是–。
string s2("hello world");
string::reverse_iterator it2 = s2.rbegin();
while (it2 != s2.rend())
{
cout << *it2 << " ";
++it2;
}
cout << endl;
algorithm
这个区间也是左闭右开
void test_string6()
{
string s1("hello world");
cout << s1 << endl;
// s1按字典序排序
//sort(s1.begin(), s1.end());
// 第一个和最后一个不参与排序
//sort(++s1.begin(), --s1.end());
// 前5个排序 [0, 5)
//sort(s1.begin(), s1.begin()+5);
cout << s1 << endl;
}
string类对象的修改操作
operate+=
push_back和append很类似,前者只能尾插一个字符,后者可以尾插一串字符串。
但是最好用的还是operate+=
string s1("hello world");
s1 += 'y';
s1 += "zzzzzzzz";
s1 += s2;
cout << s1 << endl;
insert
int main()
{
string s2("hello world");
s2.insert(0, "xxxx");
cout << s2 << endl;
char ch = 'y';
cin >> ch;
s2.insert(0, 1, ch);
cout << s2 << endl;
s2.insert(s2.begin(), 'y');
cout << s2 << endl;
s2.insert(s2.begin(), s1.begin(), s1.end());
cout << s2 << endl;
}
erase(删除)
int main()
{
string s1("hello world");
cout << s1 << endl;
// erase效率不高,慎用,和insert类似,要挪动数据
s1.erase(0, 1);
cout << s1 << endl;
//s1.erase(5);
s1.erase(5, 100);
cout << s1 << endl;
}
replace
string s2("hello world");
s2.replace(5, 1, "%20");
cout << s2 << endl;
replace效率不高,慎用,和insert类似,要挪动数据
Capacity
写一个遍历,这里要用到
因为这里返回值是char&
所以传引用返回除了可以减少拷贝构造,同时可以修改返回对象!
void test_string3()
{
string s1("hello world");
s1[0] = 'x';
cout << s1.size() << endl;
//cout << s1.length() << endl;
for (size_t i = 0; i < s1.size(); i++)
{
s1[i]++;
}
cout << endl;
const string s2("hello world");
// 不能修改
//s2[0] = 'x';
}
reserve
这个函数的作用相当于对capacity做改变
string s1("111111111");
string s2("11111111111111111111111111111111111111111111111111");
cout << s1.capacity() << endl;
// 15
s1.reserve(100);
cout << s1.capacity() << endl;
// 111
s1.reserve(20);
cout << s1.capacity() << endl;
111
传的值比当前的capacity小的话,VS中capacity的值不发生变化。
但是如果值小于16(因为有一个16字节的Buffer[]),就在堆上释放到Buffer上
会扩容,但是不一定会缩容(缩容很危险)。
所以reserve可以提前开空间
void TestPushBack()
{
string s;
// 知道需要多少空间,提前开好
s.reserve(200);
s[100] = 'x';
size_t sz = s.capacity();
cout << "capacity changed: " << sz << '\n';
cout << "making s grow:\n";
for (int i = 0; i < 200; ++i)
{
s.push_back('c');
if (sz != s.capacity())
{
sz = s.capacity();
cout << "capacity changed: " << sz << '\n';
}
}
}
resize
因为reserve没办法对扩容的空间的数据直接访问,size不会发生变化。所以我们要用resize.
int main()
{
string s1;
//s1.resize(5, '0');
s1.resize(5);
s1[4] = '3';
s1[3] = '4';
s1[2] = '5';
s1[1] = '6';
s1[0] = '7';
// 76543
// 插入(空间不够会扩容)
string s2("hello world");
s2.resize(20, 'x'); //hello worldxxxxxxxxxxxxxxxxxxxx
// 删除 只保留前五个 size变为5 但是capacity不变
s2.resize(5);
}
string operation
c_str(c兼容c++问题)
我们在写一个读文件的操作即用了string,又用了c的读文件
这就是会导致c的编译器没办法获取。
将string转换为可被c读取的方式,这样就能更好地兼容了。
find
针对这样一个“string.cpp”文件名,我们想要寻找后缀.cpp。
string file("string.cpp");
size_t pos = file.find('.');
用find来定位.的位置,那怎么把.后面的也取出来呢?
string file("string.cpp");
size_t pos = file.find('.');
//string suffix = file.substr(pos, file.size() - pos);
string suffix = file.substr(pos);
substr可以省略字符长度,自动取到末尾。
但是如果string.cpp.zip有两个后缀,那怎么把后面一个取出来呢?
rfind可以从后面往前查找。
string file("string.cpp.zip");
size_t pos = file.find('.');
//string suffix = file.substr(pos, file.size() - pos);
string suffix = file.substr(pos);
我们现在有一段很长的网域
string url("https://gitee.com/ailiangshilove/cpp-class/blob/master/%E8%AF%BE%E4%BB%B6%E4%BB%A3%E7%A0%81/C++%E8%AF%BE%E4%BB%B6V6/string%E7%9A%84%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E5%8F%8A%E4%BD%BF%E7%94%A8/TestString.cpp");
size_t pos1 = url.find(':');
string url1 = url.substr(0, pos1 - 0);
cout << url1 << endl;
通过这个,我们可以把http拿出来。但是怎么把gitee.com拿出来呢?
find可以指定位置开始查找/(默认起始位置是0)
size_t pos2 = url.find('/', pos1 + 3);
string url2 = url.substr(pos1 + 3, pos2 - (pos1 + 3));
cout << url2 << endl;
从g开始查找第一个/,我们就可以把gitee.com拿出来了。
getline
cin>>和scanf类似,在输入一行字符,当遇到空格的时候继续输入,遇到空格就停止,空格后面的内容就不再存在。
string str;
getline(cin, str,'0'); // 默认遇到换行结束 第三个位置可以自己定义结束标志
cout << str << endl;
int main()
{
// 默认规定空格或者换行是多个值之间分割
string str;
while (cin>>str)
{
cout << str << endl;
}
return 0;
}
(ctrl c杀进程退出)
to_string
可以把整型转换为字符型
int x = 0, y = 0;
cin >> x>>y;
string str = to_string(x + y);
cout << str << endl;
stoi也可以把字符型转换为整型。int z=stoi(str);