这里写目录标题
- 前言
- string的Modifiers
- operator+=
- append
- push_back
- assign
- insert
- erase
- replace
- swap
- pop_back
- String的operations
- c_str
- copy
- find
- rfind
- find_first_of
- find_last_of
- find_first_not_of和find_last_not_of
前言
本片文章我们将继续介绍string的使用,点击:string的介绍(上)该链接查看上篇文章的内容
string的Modifiers
operator+=
根据前面的operator我们可以知道这是一个string类的操作符重载,那这里重载之后的意思就是:可以直接用该操作符在对象内部的字符串后面加上一段我们想要的内容,那么这里使用的形式就有三种分别是:加上一个字符,加上一个字符串,加上一个同为string类的对象,比如说我们下面的代码:
void test8()
{
string s1("abcd");
string s2("abcd");
string s3("abcd");
string s4("efg");
s1 += "efg";
s2 += 'e';
s3 += s4;
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
cout << s3.c_str() << endl;
}
我们将这个函数运行一下看看运行结果:
对象s1后面多了一个字符串:efg,对象s2后面多了一个字符:e,对象s3的字符串后面多了对象s4内部的字符串内容,那么这就是不同的三种形式所带来的三种不同的操作结果,下面是该函数的英文介绍:
append
这个函数的功能跟上面的+=是一样的:都是在对象的字符串后面加上一段你想要的内容,但是这里的区别就在于append能够支持更多+=没有的形式:
第一种:
string& append (const string& str);
这种类型就是直接将参数中对象的字符串加到另外一个对象里面,我们来看看下面的代码:
string s1("abcd");
string s2("efg");
s1.append(s2);
cout << s1.c_str() << endl;
运行结果为:
我们可以看到对象s2中的字符串确实加到了对象s1中的字符串后面,那么这就是第一种初始化的形式。该形式对应的英文解释如下:
第二种:
string& append (const string& str, size_t subpos, size_t sublen);
第二种初始化形式相较于第一种多出了两个参数,其中subpos表示的意思就是相加开始的位置,而sublen表示的意思就是你要相加的字符串的长度,所以这种初始化的方式就是将对象中的一部分尾插到另外一个对象里面,比如说下面的代码:
string s1("abcd");
string s2("efg");
s1.append(s2);
string s3("abcd");
s3.append(s2, 0, 2);
cout << "s1的内容为"<<s1.c_str() << endl;
cout << "s3的内容为"<<s3.c_str() << endl;
s3使用append的第二种方式进行尾插的内容就是从s2的第0号字符开始往后的两个字符长度也就是ef,那么这段代码的运行结果也就如下:
既然涉及了长度,那么这里就会存在一个问题就是如果给的长度大于了开始位置到字符串结尾的长度会怎么办呢?那么面对这种情况,库就会对此做出优化:如果给的长度太大了那么他也只会尾插到字符串的结尾,不会尾插更多的内容,比如说下面的代码:
string s1("abcdef");
string s2("123456789");
s1.append(s2, 4, 20);
cout << s1.c_str() << endl;
这里将s2的一部分插到s1的后面,我们给的len的长度是20,但是下标为4的元素到字符串的结尾的长度为5,所以我们这里就只会尾插到s2对象的结尾并不会多加一些新的内容进去,所以这个段代码的运行结果就是abcdef56789,我们来看看编译器执行的这段代码为:
那么这里大家要注意一下。
该形式对应的英文解释如下:
第三种:
string& append (const char* s);
这种类型的参数是一个char类型指针,那么这种形式就是将一段字符串尾插到该对象的尾部,比如说我们下面的代码:
string s1("abcd");
s1.append("efg");
cout << s1.c_str() << endl;
这段代码的运行结果就如下:
该形式对应的英文解释如下:
第四种:
string& append (const char* s, size_t n);
这种尾插的方式也是通过字符串来进行尾插,但是有个区别就是该形式给了一个参数n,这个n的功能与上面的sublen是一样的,表示你要尾插的字符串的长度,但是有个区别就是这里的起始位置只能是字符串的开始,而不能自定义起始位置,比如说下面的代码:
string s1("12345");
s1.append("6789",3);
cout << s1.c_str() << endl;
这里尾插的字符串是"6789",给的长度为3起始位置是0,所以这里尾插的内容就是678,所以这里s1的内容就是12345678,我们来看看编译器编译的结果为:
同样的道理,如果这里的长度给的太长的话,编译器也是只会尾插到字符串的结尾,并不会尾插新的内容进去。该形式对应的英文解释如下:
第五种:
string& append (size_t n, char c);
这种形式表示的意思就是用n个字符c来进行尾插,比如说我们下面的代码:
string s1("11111");
s1.append(5, '2');
cout << s1.c_str() << endl;
我们尾插的内容就是5个字符2,所以这里打印的结果就是5个字符1和个字符2,我们可以看看这段代码运行的结果:
该形式对应的英文解释如下:
第六种:
template <class InputIterator>
string& append (InputIterator first, InputIterator last);
这种方式就是用迭代器来进行尾插,他会将你给的迭代区间的所有内容全部尾插到对应的对象里面,比如说下面的代码:
string s1("11111");
s1.append(5, '2');
string s2("abcdefg");
string::iterator it1 = s1.begin();
s2.append(it1, s1.end());
cout << s2.c_str() << endl;
这段代码的运行结果为:
因为it指向的是字符串的开头,而s1.end()指向的是字符串的结尾,所以这里打印的内容就是abcdefg1111122222,该形式对应的英文解释如下:
上面不同形式的参数介绍:
push_back
这个函数的功能就非常的单一,他只能往对象里的字符串尾插一个字符,比如说下面的代码:
string s1("abcd");
s1.push_back('e');
s1.push_back('f');
s1.push_back('g');
s1.push_back('h');
cout << s1.c_str() << endl;
这段代码的运行结果为:
这个函数没有重载成其他的形式 ,所以大家就理解他为专门尾插一个字符的函数,这个函数的英文介绍如下:
assign
这个函数也是用来修改对象中字符串的内容,但是这个函数有个特点:他会将原来的内容全部清空,再往里面填入你给的数据,所以相较于append这个函数不会保留原始的内容,但是他填入数据的形式却和append是一样的,我们可以通过下面的这张图片来看看有哪些填入数据的形式:
根据append的经验我们可以很好的使用这些不同的形式来修改对象中的字符串的内容比如说下面的代码:
string s1("abcdefg");
string s2("hijklmn");
s1.assign(s2);
cout << "assign的第一种形式修改内容的结果为:" << s1.c_str() << endl;
s1.assign(s1, 1, 3);
cout << "assign的第二种形式修改内容的结果为:" << s1.c_str() << endl;
s1.assign("opqqst");
cout << "assign的第三种形式修改内容的结果为:" << s1.c_str() << endl;
s1.assign("uvwxyz", 3);
cout << "assign的第四种形式修改内容的结果为:" << s1.c_str() << endl;
s1.assign(5, 'a');
cout << "assign的第五种形式修改内容的结果为:" << s1.c_str() << endl;
string::iterator it = s2.begin();
s1.assign(it, it + 5);
cout << "assign的第六种形式修改内容的结果为:" << s1.c_str() << endl;
这段代码的运行结果为:
大家仔细地观察这个代码就可以发现,我们用append对对象中的字符串进行修改,就算修改后的内容没有原始的字符串长,但是原始的内容我们依然一个都不会保存,这就是该函数的特性他会先将对象中的数据清空,再填入你给的数据,这个函数就非常好的理解就不多解释,大家还可以看看下面对应的英文解释:
insert
我们上面说的几个函数都是在尾部插入数据或者将原始的数据清空再填入数据,那如果我们想在字符串的任意位置插入数据呢?那这里我们就得用到insert这个函数,这个函数就可以帮助我们实现任意位置插入数据的这个功能,当然这个位置首先得是有效的,而且这个函数有着很多的参数形式,我们首先来看看这个函数对应的不同参数形式:
我们可以看到这个函数对应的不同参数形式和前面的append assign都差不多,就每个形式都多出来pos这个参数,那么这个pos表示的意思就是对应的字符串中的位置,如果说我想要在字符串中的第二个元素的前面插入一段数据的话,我们这里就得调用insert函数并且给这里的参数pos传一个1过去,那么其他的函数参数都跟前面的是一样的,那这里就可以顺理成章的理解这里的用法,我们来看看下面的代码:
string s1("123456789");
string s2("abcdefg");
s1.insert(1,s2);
cout << "insert的第一种形式修改内容的结果为:" << s1.c_str()<< endl;
s1 = "123456789";
s1.insert(2, s2, 2, 4);
cout << "insert的第二种形式修改内容的结果为:" << s1.c_str() << endl;
s1 = "123456789";
s1.insert(3, "hijklmn");
cout << "insert的第三种形式修改内容的结果为:" << s1.c_str() << endl;
s1 = "123456789";
s1.insert(4, "hijklmn",3);
cout << "insert的第四种形式修改内容的结果为:" << s1.c_str() << endl;
s1 = "123456789";
s1.insert(5, 5,'a');
cout << "insert的第五种形式修改内容的结果为:" << s1.c_str() << endl;
s1 = "123456789";
string::iterator it1 = s1.begin();
s1.insert(it1,'a');
cout << "insert的第六种形式修改内容的结果为:" << s1.c_str() << endl;
s1 = "123456789";
string::iterator it2 = s2.begin();
s1.insert(it1+6,it2,s2.end( ));
cout << "insert的第七种形式修改内容的结果为:" << s1.c_str() << endl;
s1 = "123456789";
这个代码打印的结果为:
这个就非常的简单,大家可以看看这个函数对应的英文解释:
erase
既然有任意位置的插入那也就有任意位置的删除,所以函数erase的功能就是实现任意位置的删除,这个函数就只有三种不同形式的参数
第一种形式的意思:从pos位置开始往后len个长度的数据全部删除,而且这里的len是一个无符号的整型,库给它了一个缺省值为-1,那这里表示的意思就是如果你不给它参数的话,那么它会将pos位置后面的全部数据都给删除。
第二种形式的意思:将你给的迭代器位置的字符给删除。
第三种形式的意思:将迭代器区间的内容全部都删除。
我们可以看看下面的代码:
#include<iostream>
#include<string>
using namespace std;
void test1()
{
string s1("abcdefg");
string s2("abcdefg");
string s3("abcdefg");
s1.erase(2, 3);
string::iterator it2 = s2.begin() + 2;
s2.erase(it2);
string::iterator it3 = s3.begin();
s3.erase(it3 + 4, s3.end());
cout << "s1的内容为:";
cout << s1.c_str() << endl;
cout << "s2的内容为:";
cout << s2.c_str() << endl;
cout << "s3的内容为:";
cout << s3.c_str() << endl;
}
int main()
{
test1();
return 0;
}
这个代码执行的结果为:
第一个erase是将第三个字符开始往后的3个字符全部都删除了,第二个erase是将迭代器it2位置的元素删除也就是第三个位置的字符,第三个erase是将一个迭代区间的内容全部进行那这里的迭代区间就是第5个元素到最后的一个元素,所以就有了上面的执行结果。下面是该函数的英文介绍:
replace
前面有插入数据也有删除数据,那么这里的replace函数的作用就是替换数据,他可以将任意位置的数据进行替换,其参数的形式右边如下几种:
string& replace (size_t pos, size_t len, const string& str);
string& replace (iterator i1, iterator i2, const string& str);
有了前面的经验第一种形式就非常的好理解,将pos位置往后的len个长度的数据全部替换成对象str中的字符串,第二种形式就是将迭代器it1和it2中间的数据全部都替换成对象str中的字符串,比如说下面的代码:
void test2()
{
string s1("abcdefg");
string s2("hijklmn");
string s3("1234567");
s1.replace(2,3, s3);
string::iterator it1 = s2.begin();
string::iterator it2 = s2.begin() + 3;
s2.replace(it1, it2, s3);
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
}
这段代码的运行结果为:
string& replace (size_t pos, size_t len, const string& str,
size_t subpos, size_t sublen);
第三种形式就是将参数中对象的部分数据拿来替换,subpos表示开始位置,sublen表示替换的数据长度,比如说下面的代码:
void test2()
{
string s1("abcdefg");
string s2("1234567");
s1.replace(2,3,s2,3,4);
cout << s1.c_str() << endl;
}
这段代码的运行结果如下:
string& replace (size_t pos, size_t len, const char* s);
string& replace (iterator i1, iterator i2, const char* s);
string& replace (size_t pos, size_t len, const char* s, size_t n);
string& replace (iterator i1, iterator i2, const char* s, size_t n);
我们可以将对象中的字符串拿来替换另外一个对象中的字符串,那同样的道理我们可以直接传一个字符串到这个函数里面来进行数据的替换,当然第四和第五都是整个字符串来替换,第六和第七则是部分字符串来进行替换,由参数n来决定替换的字符串的内容为多少,比如说下面的代码:
string s1("abcdefg");
string s2("abcdefg");
string s3("abcdefg");
string s4("abcdefg");
s1.replace(2, 3, "12345");
string::iterator it2 = s2.begin();
s2.replace(it2, s2.end() - 2, "12345");
s3.replace(2, 3, "12345", 2);
string::iterator it4 = s4.begin();
s4.replace(it4, s4.end() - 3, "12345", 3);
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
cout << s3.c_str() << endl;
cout << s4.c_str() << endl;
这段代码的运行结果为:
string& replace (size_t pos, size_t len, size_t n, char c);
string& replace (iterator i1, iterator i2, size_t n, char c)
我们还可以在指定的范围内用n个相同的字符来进行替换,比如说下面的代码:
string s1("abcdefg");
string s2("abcdefg");
s1.replace(2, 3, 3, '1');
string::iterator it2 = s2.begin();
s2.replace(it2, it2 + 4, 4, '1');
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
这段代码的运行结果如下:
template <class InputIterator>
string& replace (iterator i1, iterator i2,
InputIterator first, InputIterator last);
这种形式就是用两个迭代器来进行内容的替换这里的i1和i2是要替换的区间,first和last就是替换数据的区间,比如说下面的代码:
string s1("abcdefg");
string s2("123467");
string::iterator it1 = s1.begin();
string::iterator it2 = s2.begin();
s1.replace(it1, it1 + 2, it2 + 1, it2 + 3);
cout << s1.c_str() << endl;
这个代码的运行结果如下:
那么这就是replace函数的全部形式,下面是该函数的英文介绍:
swap
swap函数的作用就非常的明显就是交换两个对象中的内容,比如说下面的代码:
string s1("abcdefg");
string s2("123467");
cout << "交换前s1的内容:" << endl;
cout << s1.c_str() << endl;
cout << "交换后s2的内容:" << endl;
cout << s2.c_str() << endl;
s1.swap(s2);
cout << "交换前s1的内容:" << endl;
cout << s1.c_str() << endl;
cout << "交换后s2的内容:" << endl;
cout << s2.c_str() << endl;
这段代码的运行结果如下:
并且这里的交换不仅仅是对象中的字符串进行了交换,capacity等其他数据也发生了交换,下面是这个函数的英文介绍:
pop_back
前面有个+=的操作符重载来实现在字符串的尾部插入数据,那么与之对应的就有pop_back函数来实现对尾部的数据进行删除,这个函数没有参数,并且每次只能删除尾部的一个字符,比如说下面的代码:
string s1("abcdefg");
s1.pop_back();
cout << s1.c_str() << endl;
该代码的执行结果如下:
我们可以看到尾部的g不见了,那么这就是该函数的作用每调用一次删除字符串尾部的一个有效字符,该函数的英文介绍如下:
String的operations
c_str
这个函数我们就非常的熟悉,他可以返回一个指向对象内部字符串的指针,该函数的英文介绍如下:
如果我没理解错的话下面的date的功能跟这个函数是差不多的也是返回一个指针,大家可以自行看一下date函数的英文介绍:
copy
这个函数的功能就是将string对象中的字符串拷贝到其他的地方,比如说拷贝到一个数组里面,这个函数有三个参数,第一个参数是要拷贝到的地址,第二参数是你要拷贝的长度,第三个参数是你要拷贝的起始位置,比如说下面的代码:
string s3("abcdefg");
char arr[20];
arr[s3.length()] = '\0';
s3.copy(arr, s3.length());
cout << arr << endl;
该代码的运行结果如下:
find
我们首先来看看这个函数的功能:
这个函数的功能就是在一个对象的字符串中查找指定的内容,如果找到了那么这个函数就会返回对应内容第一次出现的位置,如果没有找到就会返回npos,而且这里的查找可以找一个字符串也可以查找一个字符,我们的库就提供了4种查找形式第一种:
size_t find (const string& str, size_t pos = 0) const;
第一个参数是一个string类的对象,第二个参数表示的是查找的起始位置,比如说我要在对象内部的第三个字符开始往后查找对象str中的字符串是否出现?那么这里我们就得把2传给这里的pos,比如说下面的代码:
void test4()
{
string s1("abcdefgabcdefg");
string s2("abcdefg");
int pos = s1.find(s2, 1);
cout << pos << endl;
}
我们想在对象s1中查找s2的内容,但是我们给的起始位置是1,也就是从第二个元素开始查找所以这个函数的返回值就不是0而是7,我们来看看这段的代码的运行结果:
第二种形式:
size_t find (const char* s, size_t pos = 0) const;
上面的那个是传递一个对象来进行对应的查找,那么这个就是传递一个字符串来进行对应的查找,同样的第二个参数pos表示的意思就是查找的起始位置,比如说我们下面的代码:
string s1("abcdefgabcdefg");
string s2("abcdefg");
int pos = s1.find(s2, 1);
cout << "字符串的起始位置为:"<< pos << endl;
int pos1 = s1.find("bcd",2);
cout << "字符串的起始位置为:" << pos1 << endl;
这里是从下标为2的地方开始进行查找,所以找到对应的位置就是下标为8,我们来看看这段代码的运行结果为:
第三种形式:
size_t find (const char* s, size_t pos, size_t n) const;
相较于第二种,第三种形式还给了一个参数n,这个n修饰的是你要查找的对应字符串,比如说你传过来的字符串是123456,那么当n的值是3的时候他就会将前三个字符作为目标在对象中进行查找也就是字符串123,比如说下面的代码:
string s1("abcdefgabcdefg");
string s2("abcdefg");
string s3("01234567");
int pos = s1.find(s2, 1);
cout << "字符串的起始位置为:"<< pos << endl;
int pos1 = s1.find("bcd",2);
cout << "字符串的起始位置为:" << pos1 << endl;
int pos2 = s3.find("123456789", 0, 3);
cout << "字符串的起始位置为:" << pos2 << endl;
这段代码的运行结果如下:
第四种形式:
size_t find (char c, size_t pos = 0) const;
这个就是查找对象中是否出现了字符c,如果找到了这个函数就会返回第一次出现的位置,比如说下面的代码:
string s1("abcdefgabcdefg");
string s2("abcdefg");
string s3("01234567");
int pos = s1.find(s2, 1);
cout << "字符串的起始位置为:"<< pos << endl;
int pos1 = s1.find("bcd",2);
cout << "字符串的起始位置为:" << pos1 << endl;
int pos2 = s3.find("123456789", 0, 3);
cout << "字符串的起始位置为:" << pos2 << endl;
int pos3 = s3.find('5', 0);
cout << "字符串的起始位置为:" << pos3 << endl;
下面是这个函数对应的英文解析:
rfind
find是从左往右进行查找,那么这里的rfind就是从右往左来进行查找,这里的参数形式和上面的find是一样的这里就不多说了,大家可以看看对应的英文解析:
find_first_of
前面的find函数是以整个字符串或者单个字符的形式来进行对应的查找,那么这里的find_first_of函数就是查找第一个出现目标字符串中字符的位置,比如说目标字符串是abcde,对象中的字符串是haibjckdlemfng,那么这个函数就会从左往右依次找第一次出现字符串abcde内容的位置,因为字符串abcde中含有字符a,而对象中的字符串第一个字符是h第二字符就是a,所以这个函数就会返回第二个元素的下标也就是1,我们来看看下面的代码:
string s1("haibjckdlemfng");
cout<<s1.find_first_of("abcde", 0)<<endl;
这段代码的运行结果如下:
这个函数同样也有四种形式,跟上面的四种形式一样这里就不多做解释:
find_last_of
与上面的函数功能类似但是这个函数是从右往左来进行查找,比如说下面的代码:
string s1("haibjckdlemfng");
cout<<s1.find_first_of("abcde", 0)<<endl;
cout << s1.find_last_of("abcde",13 ) << endl;
我们来看看这段代码的运行结果:
因为目标字符串中含有字符e,而字符e在查找的字符串中是最右边的,所以这里打印出来的结果是9,大家可以看看这个函数对应的英文解释:
find_first_not_of和find_last_not_of
这个函数的功能与上面的find_first_of函数相反,这个函数是查找第一个未在目标字符串的字符,并返回对应的位置,同样的道理find_last_not_of就是从右往左来进行查找未在目标字符串出现的字符,这里就不多说了与上面的类似,大家可以看看对应的英文注解: