一、简单认识string类
1.string类的简介

string是用来表示字符序列的对象,标准string类为一些对象提供了类似于标准字节容器的接口,而且添加了特殊设计去操作单字节。是basic_string类模板针对char类型的实例化。它独立于所采用的编码来处理字节。
2.string类的默认成员函数

1.构造函数

C++98共有7种构造函数

- string():默认构造函数,无参数。构造一个空字符串,有0个字符。
- 拷贝构造,使用字符串str来拷贝构造一个字符串。
- 复制str字符串从pos位置开始的len个字符,如果字符串太短或者len为string::npos就直接复制到结尾。(string::npos是静态成员常数,在表示len时取值最大,意味着直到字符串结束,作为返回值时表示没有匹配。)
- 从c风格构造一个字符串,接受const char *s 的参数。
- 从s指向的字符数组中复制前n个字符。
- 使用n个字符C填满字符串。
cpp
int main()
{
string s1; //1
string s2("hello world"); //4
string s3(s2); //2
string s4(s2, 6, 5); //3
string s5("xxxxxxxxx", 3);//5
string s6(5, 'o'); //6
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
cout << s4 << endl;
cout << s5 << endl;
cout << s6 << endl;
return 0;
}

2.析构函数

销毁对象,释放字符串通过分配器分配的所有内存。
3.赋值重载

赋值重载的功能是为字符串分配新值,替换当前内容。参数可以是string类类型对象,字符串,单个字符。
cpp
s4 = s2;
s5 = "天天开心";
s6 = 'x';
cout << s4 << endl;
cout << s5 << endl;
cout << s6 << endl;

3.迭代器
迭代器是用来遍历和访问字符串的一种方式。他的底层实现和用法都类似于指针,可以对字符串进行修改,任何迭代器都属于他的类域。

迭代器一般有四种:iterator,const_iterator,reverse_iterator,const_reverse_iterator,分为正向迭代器,反向迭代器,普通字符串迭代器,const修饰的字符串迭代器,编译器会自动匹配最合适的迭代器。前面加C确定了是常量字符串。
使用方法:
cpp
void test()
{
string s("hello world");
//正向迭代器
string::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
it++;
}
cout << endl;
//反向迭代器
string::reverse_iterator rit = s.rbegin();
while (rit != s.rend())
{
cout << *rit << " ";
rit++;
}
cout << endl;
//const
const string s1("hello world");
string::const_iterator cit = s1.begin();
while (cit != s1.end())
{
cout << *cit << " ";
cit++;
}
cout << endl;
}
遍历字符串的三种方式:
1.下标+\[\]:通过下标可以访问字符串,也可以直接修改字符串内容。
cpp
string s("hellooooo!");
//1.下标+[]
for (int i = 0; i < s.size(); i++)
{
cout << s[i];
}
cout << endl;
s[0] = 'e';
cout << s << endl;

2.迭代器:通过迭代器访问字符串,用法类似指针,所以它也可以修改字符串内容。
cpp
string s("hellooooo!");
string::iterator it = s.begin();
while (it != s.end())
{
*it += 2;
cout << *it;
it++;
}
cout << endl;

3.范围for:范围for可以遍历字符串,auto用来自动赋值,自动迭代,自动判断结束。在底层也是通过迭代器来实现,把*it的值赋给ch,所有容器也都支持范围for,因为所有容器支持迭代器。ch是将字符串中每个字符遍历拷贝给ch,修改ch不影响原字符串。因为ch仅仅是字符串的拷贝。若想修改字符串,需要将auto改成auto&。
cpp
for (auto ch : s)
{
cout << ch;
}
cout << endl;
auto和范围for
auto
- 在早期C++中,使用auto修饰的变量,是具有自动存储器的局部变量,后来这个不重要了。C++11赋予了其新的含义,auto不再是一个存储类型提示符,而是作为新的类型提示符来指示编译器,auto声明的编译器必须在编译器编译时推导而得。
- auto声明指针类型时auto和auto*没有任何区别,但声明引用时必须加&。
- 在同一行声明多个变量时,必须是相同类型的变量,否则将会报错,编译器只会对第一个类型进行推导,用推导出来的类型定义其他变量。
- auto不能用来做参数,可以用来做返回值,但建议谨慎使用。
- auto不能用来声明数组。
注意:auto的主要作用是用来简化代码,替换长类型,因此必须知道类型,否则无法推导,但这也牺牲了可读性。(typeid().name()是用来查看类型)。
范围for
- 对于一个有范围的集合,使用范围for可以自动迭代,自动取数据,自动判断结束。
- 范围for适用于容器和数组。
- 他的底层就是替换为迭代器,可以从汇编的角度看到。
cpp
int main()
{
//test();
int arr[] = { 0,1,2,3,4,5,6,7,8,9 };
for (auto a : arr)
{
cout << a << " ";
}
cout << endl;
string s("hello world!");
for (auto ch : s)
{
cout << ch;
}
cout << endl;
return 0;
}
4.容量相关

- size和length都是返回字符串的长度,考虑到C++发展历史,length先出来,size是为了后面适应STL后出来,他们的功能相同。
- max_size是返回字符串最大值,由于技术上的缺陷,返回的实际是整形的最大值,一般不常用。
- capacity返回字符串的容量,不包括\0,实际开的空间会比capacity多。在vs下有buffer,字符串内容少时就放在buffer中。
- reserve的功能是提前开好空间,避免扩容,提高效率。(当size = 10,capacity = 20时,如果要开的空间n>20,确定一定会开空间,但是当n<10或10<n<20时,不具有约束力,在不同平台下情况可能不同,在vs平台不缩容,在g++会缩容。
- clear清除字符串中数据,不清除容量。
- empty,判断字符串是否为空,不包括\0。
5.元素遍历

- \[\] 返回pos位置的字符,用断言来判断是否越界。
- at越界会抛异常
6.修改相关

1.operator+=

拼接字符串,他的参数可以是string类类型对象,字符串,单个字符。
cpp
int main()
{
string s("hello");
string ss("world");
s += ss;
cout << s << endl;
s += "xxxxxxx";
cout << s << endl;
s += 'z';
cout << s << endl;
return 0;
}
2.append

功能和+=类似,一般+=用的比较多。
cpp
string s1("hi");
s1.append(s);
cout << s1 << endl;
s1.append("!!!");
cout << s1 << endl;
s1.append(1,'c');
cout << s1 << endl;
3.push_back

尾插。
cpp
s1.push_back('v');
cout << s1 << endl;
4.assign

赋值,会覆盖原字符串的内容,一般用处不大。
cpp
string s3("iiitttssss");
s1.assign(s3);
cout << s1 << endl;
s1.assign("hiiiiiiiii");
cout << s1 << endl;
s1.assign(5, 'a');
cout << s1 << endl;
5.insert

在pos位置插入,可以是类类型对象,字符串或者他们的一部分,也可以是单个字符,可以是头插或者中间插入。
cpp
string s("hello");
string ss("world");
s.insert(3, ss);
cout << s << endl;
s.insert(0, "xxxx");
cout << s << endl;
s.insert(0, 2, 'c');
cout << s << endl;
s.insert(s.begin(), 'h');
cout << s << endl;
6.erase

删除字符串的一部分。
cpp
s.erase(0, 3);
cout << s << endl;
s.erase(s.begin());
cout << s << endl;
s.erase(s.begin(), s.end());
cout << s << endl;
7.replace

replace可以替换字符串中的部分内容。
cpp
string s("h e l l o w o r l d");
//s.replace(5, 1, "%%");
//cout << s << endl;
size_t pos = s.find(' ');
while (pos != string::npos)
{
s.replace(pos, 1, "%%");
cout << s << endl;
pos = s.find(' ', pos + 2);
}
注意:insert ,erase,replace性能较差,应该谨慎使用。
8.swap

交换此容器(即当前字符串对象)与另一个字符串对象 str 的内容。两者的长度可以不同。
7.string一些其他操作

c_str
获取C风格的字符串,返回一个指向以 \0 结尾的字符数组的指针。
cpp
string file;
cin >> file;
FILE* fout = fopen(file.c_str(), "r");
char ch = fgetc(fout);
while (ch != EOF)
{
cout << ch;
ch = fgetc(fout);
}
fclose(fout);
data
与c_str功能类似。
find

在字符串内查找子串或字符。
cpp
string s("test.cpp");
size_t t = s.find('.');
string subffer = s.substr(t);
cout << subffer << endl;
rfind
和find功能相同,但是是倒着找。
cpp
string s("test.cpp.zip");
size_t t = s.rfind('.');
string subffer = s.substr(t);
cout << subffer << endl;
find_first_of find_last_of
在字符串中搜索任意一个 指定的字符集合中的字符,返回第一个匹配到的位置。find_last_of() :与上面类似,但是从字符串末尾开始向前搜索,返回最后一个匹配指定字符集合的位置。
cpp
string str("Please, replace the vowels in this sentence by asterisks.");
size_t found = str.find_first_of("aeiou");
while (found != string::npos)
{
str[found] = '*';
found = str.find_first_of("aeiou", found + 1);
}
cout << str << '\n';
find_first_not_of() :在字符串中搜索不属于指定字符集合中的第一个字符。
find_last_not_of() :从字符串末尾开始 向前搜索,查找第一个不属于指定字符集合的字符。
substr

通过一个类类型对象的一部分构建一个新的类类型对象。