C++【string类的使用】(下)
上一篇文章:C++【string类的使用】(上)
文章目录
- 1. string类获取元素
- 1.1 operator[] (重点) 和 at
- 1.2 front 和 back
- 2. string类对象的修改操作
- 2.1 push_back
- 2.2 append
- 2.3 operator+= (重点)
- 2.4 insert
- 2.5 assign
- 2.6 erase
- 2.7 replace
- 2.8 pop_back
- 3. string的操作
- 3.1 c_str (重点)
- 3.2 data(与size、length类似,我们一般不使用)
- 3.3 get_allocator
- 3.4 copy
- 3.5 substr
- 3.6 compare
- 4 string的查找
- 4.1 find (重点) 和 rfind
- 4.2 find_first_of 和 find_last_of
- 4.3 find_first_not_of 和 find_last_not_of
- 5. strinf类的非成员函数
- 5.1 operator+
- 5.2 operator<< 和 operator>> (重点)
- 5.3 relational operators (重点)
- 5.4 swap
- 5.5 getline (重点)
- 结语
1. string类获取元素
1.1 operator[] (重点) 和 at
他们两个的功能几乎一样,都是返回string中一个字符的引用
Returns a reference to the character at position pos in the string.
返回string中第pos位置的引用
Returns a reference to the character at position pos in the string.
返回string中第pos位置的引用
The function automatically checks whether pos is the valid position of a character in the string (i.e., whether pos is less than the string length), throwing an out_of_range exception if it is not.
函数会自动检查 pos 是否是字符串中字符的有效位置(即 pos 是否小于字符串长度),如果不是,则抛出 out_of_range 异常。
这是at
和operator[]
不同的点,operator[]是用assert
进行检查下标,当下标不合法直接报错,at是抛异常
string s1("hello world");
//operator[] 返回的是引用
cout << s1[1] << endl;
s1[1] = 'x';
cout << s1 << endl;
string s1("hello world");
try
{
//at 和 operator[]的功能一样
cout << s1.at(1) << endl;
s1.at(-1) = 'e';
cout << s1 << endl;
}
catch (const exception& e)
{
cout << e.what() << endl;
}
但是他们的功能上是完全相同的
string s1("hello world");
try
{
//at 和 operator[]的功能一样
cout << "at:" << s1.at(1) << endl;
s1.at(1) = 'e';
cout << "at:" << s1 << endl;
}
catch (const exception& e)
{
cout << e.what() << endl;
}
//operator[] 返回的是引用
cout <<"operaor[]:" << s1[1] << endl;
s1[1] = 'x';
cout << "operaor[]:" << s1 << endl;
1.2 front 和 back
返回第一个和最后一个字符的引用
Returns a reference to the first character of the string.
返回字符串中第一个字符的引用
Unlike member string::begin, which returns an iterator to this same character, this function returns a direct reference.
不像成员变量string::begin()一样,返回指向同一字符的迭代器,front函数直接返回第引用
This function shall not be called on empty strings.
这个函数不能在空字符串上使用
Returns a reference to the last character of the string.
返回string中最后一个字符的引用
This function shall not be called on empty strings.
这个函数不能在空字符串上使用
string s1("hello world");
//back --> 返回最后一个有效字符的引用
cout << s1.back() << endl;
//front --> 返回第一个有效字符的引用
cout << s1.front() << endl;
2. string类对象的修改操作
2.1 push_back
push_back我们很熟悉了,就是在在字符串后尾插字符c
Appends character c to the end of the string, increasing its length by one.
添加一个字符在string的末尾,string的size增加一
string s1("hello world");
string s2("0123456789abcd");
//push_back(尾插)
s1.push_back('x');
cout << s1 << endl;
//只能一个字符一个字符的插入
//s1.push_back("abc");
只能一个字符一个字符的插入,插入字符串会报错
2.2 append
append就支持很多了,但我直接用几个来演示,其他会用文字说明
Extends the string by appending additional characters at the end of its current value:
在字符串当前值的末尾添加额外字符,从而扩展字符串
- string
Appends a copy of str.
添加拷贝一个字符串
- substring
Appends a copy of a substring of str. The substring is the portion of str that begins at the character position subpos and spans sublen characters (or until the end of str, if either str is too short or if sublen is string::npos).
在末尾添加str的子串。子串是 str 中从字符位置 subpos 开始并跨越 sublen 字符的部分(如果 str 太短或 sublen 为 string::npos 则直到 str 结束)。
- c-string
Appends a copy of the string formed by the null-terminated character sequence (C-string) pointed by s.
在末尾追加由 s 指向的常量字符串的拷贝。
- buffer
Appends a copy of the first n characters in the array of characters pointed by s.
在末尾追加字符串的前n个字符
- fill
Appends n consecutive copies of character c.
在末尾添加n个c字符
- range
Appends a copy of the sequence of characters in the range [first,last), in the same order.
以相同的顺序附加 [first,last] 范围内字符序列的副本。
演示前三个(添加string类,添加字串,添加字符串)
string s1("hello world");
string s2("10001 ");
//append (尾插)
// 插入string
s1.append(s2);
cout << s1 << endl;
//尾插子串
s1.append(s2,2);
cout << s1 << endl;
//尾插字符串
s1.append("aaa");
cout << s1 << endl;
2.3 operator+= (重点)
在string尾部追加字符时,s.push_back© / s.append(1, c) / s += 'c’三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
string s1("hello world");
string s2("10001 ");
s1 += 'x';
cout << s1 << endl;
s1 += " 123 ";
cout << s1 << endl;
s1 += s2;
cout << s1 << endl;
2.4 insert
使用insert可以实现任意位置的插入,但是不建议使用,因为非尾插都会造成数据的挪动,会造成性能下降。
所以我们也就不讲解了。
迭代器头插
//insert(任意位置插入)
s1.insert(s1.begin(), s2.begin(), s2.end());
cout << s1 << endl;
2.5 assign
assgin的功能类似赋值,但是string重载全局的operator=,所以这个函数也就被废弃掉了
所以也就不讲解这个函数了。
string s1("hello world");
string s2("10001 ");
//assign(赋值) 类似 s1 = x;
s1.assign(5, 'x');
cout<< "s1:" << s1 << endl;
s1.assign(s2);
cout << "s1:" << s1 << endl;
2.6 erase
删除string中的有效字符,其实删除也会挪动数据,也会造成性能的下降,所以我们使用的也不是很多。
所以也就不详细讲解了。
erase的四种删除方式
- 默认全删除
string s1("hello world");
//erase 删除字符
s1.erase();//默认全删除
cout << s1 << endl;
- 删除部分字符
string s1("hello world");
//erase 删除字符
s1.erase(0, 5);//删除部分字符
cout << s1 << endl;
- 删除迭代器所指向的字符
string s1("hello world");
//erase 删除字符
s1.erase(s1.begin());//删除指针所指向的字符
cout << s1 << endl;
- 删除迭代器区间的字符
string s1("hello world");
//erase 删除字符
s1.erase(s1.begin(), s1.end() - 5);//删除迭代器区间的字符
cout << s1 << endl;
2.7 replace
Replaces the portion of the string that begins at character pos and spans len characters (or the part of the string in the range between [i1,i2)) by new contents:
用新内容替换字符串中从字符 pos 开始、跨 len 字符的部分(或字符串中 [i1,i2) 之间范围内的部分):
replace 替换 (函数的参数与重载和append和构造函数一样)
relpace可以多替换少,也就是可以将一个字符替换成字符串,当然这一定会发生数据的挪动,如果替换后的size超过了capacity,那么replace会自动扩容
replace的常规使用方式为
//replace(位置,替换的字符个数,要替换的字符)
string s1("hello world");
//replace 替换 (大体函数和append和构造函数一样)
//replace(位置,替换的字符个数,要替换的字符)
s1.replace(5, 1,"%%");
cout << s1 << endl;
2.8 pop_back
顾名思义,删除最后一个字符
string s1("hello world");
//poo_back 顾名思义 尾删
s1.pop_back();
cout << s1 << endl;
3. string的操作
3.1 c_str (重点)
这个函数的目的是为了适配只有C语言接口的函数
string s1("hello world");
//这是为了兼容C语言
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);
3.2 data(与size、length类似,我们一般不使用)
文档链接:https://legacy.cplusplus.com/reference/string/string/data/
3.3 get_allocator
空间配置器,我们现在还不需要了解
文档链接:https://legacy.cplusplus.com/reference/string/string/get_allocator/
3.4 copy
将string的内容拷贝出去
//copy 将字符串拷贝出来
char buffer[20];
//copy(拷贝的目的地, 拷贝的个数, 起始点)
s1.copy(buffer, 5, 0);
3.5 substr
substr 拷贝字串给其他对象,比copy好用 使用copy前还需要先创建一个对象
string s1("hello world");
//substr 拷贝字串给其他对象
//比copy好用 使用copy前还需要先创建一个对象
string s2 = s1.substr(0, 5);
cout << s2 << endl;
3.6 compare
函数的作用是比较两个字符串,但是string重载了关系运算符,所以这个函数也就被废弃了
文档链接:https://legacy.cplusplus.com/reference/string/string/compare/
4 string的查找
其实也是第三点的内容,只是我单独提出来了。
4.1 find (重点) 和 rfind
find顾名思义,就是找元素,在字符串中按顺序寻找第一次出现的指定元素。
rfind就是从后往前找第一个出现的指定元素
我们主要讲解find
,因为rfind
的就是反方向的find
When pos is specified, the search only includes characters at or after position pos, ignoring any possible occurrences that include characters before pos.
如果指定了 pos,则搜索只包括位置 pos 上或之后的字符,而忽略包括位置 pos 之前字符的任何可能出现的情况。(pos默认为0,string的开头)
Notice that unlike member find_first_of, whenever more than one character is being searched for, it is not enough that just one of these characters match, but the entire sequence must match.
请注意,与 find_first_of 成员不同的是,只要要搜索的字符超过一个,仅仅其中一个字符匹配是不够的,整个序列都必须匹配。
也就是说,如果要find查找
"abcde"
这个字符串,find是必须一一对应的,中间不能断开(也就是说查找到的必须是"abcde"
),而find_frist_of
是不管是否一一对应,只要查找到的字符是"abcde"
中任意一个字符,就会返回被查找字符的位置
rfind的文档链接:https://legacy.cplusplus.com/reference/string/string/rfind/
string s("hello(1) world . hello(2) c++ 111");
//查找字符串
int find = s.find("hello");
string s1 = s.substr(find);
cout << "find(\"hello\"):" << s1 << endl << endl;
//可以设置从哪里开始找
find = s.find("hello", 1);
s1 = s.substr(find);
cout<< "find(\"hello\", 1):" << s1 << endl << endl;
//可以找字符
find = s.find('.');
s1 = s.substr(find);
cout << "find('.'):" << s1 << endl << endl;
//查找string类
string s2("c++");
find = s.find(s2);
s1 = s.substr(find);
cout << "find(s2):" << s1 << endl << endl;
//rfind 从后往前找
find = s.rfind("hello");
s1 = s.substr(find);
cout <<"rfind(\"hello\"):" << s1 << endl;
4.2 find_first_of 和 find_last_of
我们不要被名字骗了,find_first_of
如果我们通过名字来猜他的用法,基本上就会认为他是查找第一个出现的字符,但是但是,find()
函数不就能进行这样的操作吗,为什么还要弄一个多余的函数?
那么这也就说明了,这个函数并不是这个功能,而是搜索字符串中与其参数中指定的任意字符相匹配的第一个字符。
就是在原字符串中查找指定字符串中的任意字符,如果有一个字符与指定字符串中的任意一个字符匹配,那么不会继续查找,而是直接返回这个字符的位置
当然,其他地方与正常的find()函数一样,都可以指定查找的开始位置、查找string类
所以比起find_first_of
,find_any_of
这个名字更符合这个函数,但没办法,谁叫设计函数名的不是我们呢
find_last_of
,其实就是反向查找,就类似rfind
+find_first_of
,反向寻找的find_first_of
。
void SplitFilename(const std::string& str)
{
std::cout << "Splitting: " << str << '\n';
std::size_t found = str.find_last_of("/\\");
std::cout << " path: " << str.substr(0, found) << '\n';
std::cout << " file: " << str.substr(found + 1) << '\n'<< '\n';
}
void test_string_find()
{
//find_frist_of (从前往后找任意字符) 其实更应该叫 find_any_of
std::string str("Please, replace the vowels in this sentence by asterisks.");
std::cout << str << '\n';
std::size_t found = str.find_first_of("abcde");
while (found != std::string::npos)
{
str[found] = '*';
found = str.find_first_of("abcde", found + 1);
}
std::cout << str << '\n'<< '\n';
//find_last_of (从后往前找任意字符) 感觉 rfind_any_of 更合适
std::string str1("/usr/bin/man");
std::string str2("c:\\windows\\winhelp.exe");
SplitFilename(str1);
SplitFilename(str2);
}
文档链接:find_first_of
文档链接:find_last_of
4.3 find_first_not_of 和 find_last_not_of
其实find_frist_not_of
和 find_last_not_of
,功能就是与上面两个相反,查找不属于()里面的元素,这里不详细讲解了
文档链接:find_first_not_of
文档链接:find_last_not_of
5. strinf类的非成员函数
5.1 operator+
为了实现字符串加类 由于成员变量第一个参数被this占用,所以想要实现字符串+string必须实现为全局函数
文档链接:operator+
//operator+
//为了实现字符串加类 由于成员变量第一个参数被this占用,所以想要实现字符串+string必须实现为全局函数
string s1("hello world");
string s2 = s1 + "abc";
cout << s2 << endl << endl;
string s3 = "abc" + s1;
cout << s3 << endl << endl;
5.2 operator<< 和 operator>> (重点)
与我们Date类的重载是类似的,都是为了使用习惯而设计成全局函数
文档链接:operator<<
文档链接:operator>>
string s1("hello world");
//operator<< 原因和data类是一样的,在类内部写就只能是 s1 << cout;
//但这不符合我们的使用习惯,所以就在全局定义
cout << s1 << endl;
//operator>> 同理
cin >> s1;
cout << s1;
5.3 relational operators (重点)
elational operators(这就是比较运算符的重载) 是比compare更好的函数
文档链接:relational operators
string s1("hello world");
string s2 = s1 + "abc";
cout << s2 << endl << endl;
string s3 = "abc" + s1;
cout << s3 << endl << endl;
//relational operators(这就是比较运算符的重载) 是比compare更好的函数
//比较的是第一个字符的ASCII码值
cout << (s1 > s3) << endl;
5.4 swap
全局的swap,但几乎不会用到。
文档链接:swap
5.5 getline (重点)
getline 是控制cin>>string时的读取
正常cin是读到 空格 或者 换行就会停止读取,将' '
或'\n'
后面的元素停留在缓冲区
重新读取也不会读取到' '
和'\n'
文档链接:getline
string s1("hello world");
//getline 是控制cin>>string时的读取
//正常cin是读到 空格 或者 换行就会停止读取,将' 'or'\n'后面的元素停留在缓冲区
//重新读取也不会读取到' 'or'\n'
getline(cin, s1);
cout <<"getline(cin, s1):" << s1 << endl << endl;
//getline还能自己定义分割符
getline(cin, s1, '#');
cout << "getline(cin, s1, '#'):" << s1 << endl;
结语
那么这次的分享就到这里结束了~
最后感谢您能阅读完此片文章~
如果您认为这篇文章对你有帮助的话,可以用你们的手点一个免费的赞并收藏起来哟~
如果有任何建议或纠正欢迎在评论区留言~
也可以前往我的主页看更多好文哦(点击此处跳转到主页)。