这一讲,我们接着介绍string类的使用。
首先,我来讲解一下string的尾插

这三个函数都可以用来尾插,我们先介绍push_back

push_back是最直接的函数,它能实现的功能只有一个那就是在字符串的后边追加一个字符,只能追加一个字符,这要和后边讲解的方法做一个区分。
cpp
void test_push_back()
{
string s("hello world");
s.reserve(100);
for (int i = 0; i < 100; i++)
{
s.push_back('x');
}
cout << s << endl;
cout << s.size() << " " << s.capacity() << endl;
}

接下来介绍一下append

这里提供了很多种重载,我只介绍一些常用的。
和push_back不同的是,append支持追加字符串,不止是string类型的字符串还可以追加C语言风格的char*类型的字符串。
此外,append还支持追加string字符串的指定子串,用第二种方式传指定区域,若超出范围则追加到末尾位置。
当然,append也可以实现追加单个字符的功能,但设计的比较麻烦,如上图第五种,只能指定n和char两个参数,意为传入n个字符c,如果你只想追加一个,并没有因此设计单独的接口,只能传1,c。
cpp
void test_append()
{
//追加字符串
//string
string s("hello world");
string s1("abcde");
s.append(s1);
cout << s << endl;
//const char*
s.append("xxxx");
cout << s << endl;
//追加单个字符
s.append(1, 'k');
cout << s << endl;
//追加n个字符
s.append(7, 'z');
cout << s << endl;
}

接下来介绍一下+=,这是运算符重载函数。

+=是最简约,也是最容易理解的尾插方式。
显然这三种情况分别对应插入string,C语言风格的字符串,单个字符。
cpp
void test_operator1()
{
//operator+=
string s("hello world");
s += 'c';
cout << s << endl;
s += " askfhlak";
cout << s << endl;
string s1(" qqqqqq");
s += s1;
cout << s << endl;
}

那么尾插就已经介绍完了,接下来我介绍一下普通的插入。

普通插入其实和append有点像,也是实现了很多种重载。和尾插的本质区别是指定位置。
唯一有差别的是当我们想要插入单个字符或者多个重复字符时,需要指定位置,指定插入个数,换言之并没有为插入单个字符做单独接口。
cpp
void test_insert()
{
string s("hello world");
s.insert(0, "fasf");
cout << s << endl;
string s1("qqqqxxxx");
s.insert(5, s1);
cout << s << endl;
s.insert(0, 1, 'd');
cout << s << endl;
s.insert(4, 10, 's');
cout << s << endl;
}

值得注意的是,insert还支持迭代器传参。但是迭代器传参只能插入单个字符或者多个重复字符


插入讲完后我来讲一下删除,删除主要用的是erase函数

erase提供的三种重载,第一种是从指定位置默认是第一个位置开始往后删除len长度的字符,如果len长度超出范围,则删除到结尾为止。第二种则是删除指定位置的字符,这里是迭代器传参。第三种则是删除指定区间的字符。
cpp
void test_erase()
{
string s("123456dfasssssssssssfhqqqqxxxxello world1654321");
s.erase(0, 3);
cout << s << endl;
s.erase(s.begin());
cout << s << endl;
s.erase(s.end()-1);
cout << s << endl;
s.erase(5, 13);
cout << s << endl;
s.erase(s.begin(), s.end() - 1);
cout << s << endl;
}

这里写的还是挺复杂的,稍不留神就会出现意料之外的效果。
对于头删,我们这里的实现方式可以是传坐标也就是erase(0,1),代表从0位置开始删长度为1,也可以直接传begin的迭代器。对于迭代器删除,值得注意的是删除的是当前迭代器所指位置地字符,但是第三种地范围则是左闭右开,假如我们要尾删,第二种必须传end()-1,但是如果要删除包含尾元素,第三种就必须传end()。
插入删除介绍完后我介绍一下查找相关的操作

首先c_str

该函数意味着将string类型转变为C语言支持的字符串类型。

swap意味着交换两个string类型变量的值。
接下来介绍一下find函数

四种重载方式,第一种第二种分别是从指定位置开始查询,查询的内容是string类型以及C语言字符串类型即const char* ,第三种是从某一位置出发,查找指定长度。第四种是查找指定的字符,其中,当从pos位置查找,若成功则返回第一个串的起始下标,若失败则返回npos。
cpp
void test_find()
{
string s("hello worldhellohellohello");
size_t pos = s.find("hello");
cout << pos << endl;
cout << s.find("hello", pos + 1) << endl;
string s1("hello");
cout << s.find(s1) << endl;
cout << s.find('c', 0) << endl;
cout << s.find(' ', 0) << endl;
}

讲到这里不妨顺带提一下npos

npos虽然赋值为-1但其实是一个很大的数字,因为-1在内存中以补码存储。

介绍了find,rfind其实是一样的就不讲解了。
cpp
void test_rfind()
{
string s("hello worldhellohellohello");
size_t pos = s.rfind("hello");
cout << pos << endl;
cout << s.rfind("hello", pos - 1) << endl;
string s1("hello");
cout << s.rfind(s1) << endl;
cout << s.rfind('c') << endl;
cout << s.rfind(' ') << endl;
}

接下来看一下这两组

先看第一个find_first_of函数,感觉从字面意思上理解这个函数,他达成的效果和find没什么区别,找第一个嘛,但其实并没有这么简单。

和之前类似,就不过多讲解,简单看一下达成效果。
cpp
void test_find_first_of()
{
string s("The quick brown fox jumps over the lazy dog.");
string s1("aeiou");
size_t found = s.find_first_of(s1);
while (found != string::npos)
{
s[found] = '*';
cout << s << endl;
found = s.find_first_of(s1);
}
}

所以,find_first_of其实是find_first_any_of,在我们传入的字符串中,匹配到其中任意一个字符即返回其坐标。
其他三者区别不大,我只提供测试代码,不做具体讲解。
cpp
void test_find_first_of()
{
string s("The quick brown fox jumps over the lazy dog.");
string s1("aeiou");
size_t found = s.find_first_of(s1);
while (found != string::npos)
{
s[found] = '*';
cout << s << endl;
found = s.find_first_of(s1);
}
}
void test_find_last_of()
{
string s("The quick brown fox jumps over the lazy dog.");
string s1("aeiou");
size_t found = s.find_last_of(s1);
while (found != string::npos)
{
s[found] = '*';
cout << s << endl;
found = s.find_last_of(s1);
}
}
void test_find_last_not_of()
{
string s("The quick ");
string s1("aeiou*");
size_t found = s.find_last_not_of(s1);
while (found != string::npos)
{
s[found] = '*';
cout << s << endl;
found = s.find_last_not_of(s1);
}
}
void test_find_first_not_of()
{
string s("The quick ");
string s1("aeiou*");
size_t found = s.find_first_not_of(s1);
while (found != string::npos)
{
s[found] = '*';
cout << s << endl;
found = s.find_first_not_of(s1);
}
}

接下来介绍一下substr

截取子串,传参从某个位置开始置某个位置结束。
cpp
void test_substr()
{
string s("hello worldhellohellohello");
cout << s.substr(3, 7) << endl;
cout << s.substr(15) << endl;
}

接下来我讲一下+的运算符重载

和以往不同的是+重载并没有在string类中实现,因为如果在类中实现,第一个操作数默认是自己类型的引用,但+应该支持第一个参数为字符或者字符串。

一般来讲=赋值运算符重载函数是相当常用的,它支持传入字符stringC风格字符串三种。
cpp
void test_operator2()
{
string s("auifhk");
s = s + "xxxxxxxxxxx";
cout << s << endl;
s = s + '9';
cout << s << endl;
string s1("[[[[[[[");
s = s + s1;
cout << s << endl;
}

最后,我简单介绍一下getline函数

这是用来指定输入时边界符的,一般来讲我们输入一个' ',就会默认停止,用这个可以自己指定,默认是'\n'
关于string类的使用至此结束。
接下来会讲一下模拟实现