[C++编程笔记] 02 C++字符串总结
联系作者:359152155@qq.com
0. 概要
C++标准库提供了诸多字符串类型,它们都是通过模板 std::basic_string
特例化而来的。如下:
类型 | 定义 |
---|---|
std::string | std::basic_string<char> |
std::wstring | std::basic_string<wchar_t> |
std::u8string (C++20) | std::basic_string<char8_t> |
std::u16string (C++11) | std::basic_string<char16_t> |
std::u32string (C++11) | std::basic_string<char32_t> |
std::pmr::string (C++17) | std::pmr::basic_string<char> |
std::pmr::wstring (C++17) | std::pmr::basic_string<wchar_t> |
std::pmr::u8string (C++20) | std::pmr::basic_string<char8_t> |
std::pmr::u16string (C++17) | std::pmr::basic_string<char16_t> |
std::pmr::u32string (C++17) | std::pmr::basic_string<char32_t> |
由于这些类都有相同的接口形式,因此下面只以std::string
为例进行介绍,其他类型大同小异。
1. 字符串字面量的字符编码
const char *a = "hello world, 你好世界"; // 单字节字符, 具体编码取决于平台
const char *b = u8"hello world, 你好世界"; // utf-8编码
const char16_t *c = u"hello world, 你好世界"; // unicode16编码
const char32_t *d = U"hello world, 你好世界"; // unicode32编码
const wchar_t *e = L"hello world, 你好世界"; // 宽字符, 具体编码取决于平台
2. string初始化
string s1; | 默认初始化,初始化为空串 |
string s2{}; string s2{‘a’, ‘b’, ‘c’, …}; | 使用初始化列表初始化s2 |
string s3(n, ‘c’); | s3初始化为连续n个字符’c’组成的串 |
string s4(str); string s4 = str; | s4初始化为str的副本 |
string s5(c_str); string s5 = c_str; | s5初始化为c风格字符串c_str的副本(除去字面量最后的空字符) |
string s6(str, pos); string s6(str, pos, cnt); | 使用str的子串初始化s6,pos和cnt用来指定范围,cnt缺省时表示到str结尾 |
string s7(c_str, cnt); | 使用c风格字符串c_str的前cnt个字符初始化s7 |
string s8(first_iter, last_iter); | 使用迭代器范围[first_iter, last_iter)来初始化s8 |
3. string基本操作
判断string是否空串
s.empty() // 如果是空串返回true
返回string中字符个数
auto n = s.size(); // 返回值为string::size_t类型,C++标准未指明它的具体类型,在不同平台会有不同定义,因此我们无法确定它具体是什么类型,但可以确定的是它一定是unsigned的。
随机访问string中的元素
- 方法1. 使用
[]
访问:
此时如果pos超出范围会发生未定义的行为,因此必须先检查下标值是否正确。auto &c = s[pos];
- 方法2. 使用
at
成员函数访问:
此时如果pos超出范围会抛出auto &c = s.at(pos);
std::out_of_range
异常,因此可以事后捕获。
访问string首/尾位置的元素
auto &c1 = s.front();
auto &c2 = s.back();
遍历string中的元素
// 1. 普通for循环遍历
for (auto i = 0; i < str.size(); ++i) { // 正向
str[i];
}
for (auto i = str.size(); i !=0; --i) { // 反向
str[i-1];
}
// 2. 范围for遍历
for (auto &itm : str) {
itm;
}
// 3. 迭代器遍历
for (auto iter = str.begin(); iter != str.end(); iter++) { // 正向
*iter;
}
for (auto iter = s5.rbegin(); iter != s5.rend(); iter++) { //反向
*iter;
}
字符串比较
// 注意:string的比较是大小写敏感的
s1 == s2 // 判断是否相等
s1 != s2 // 判断是否不相等
// 以下是按字符的字典序进行大小比较
s1 > s2
s1 >= s2
s1 < s2
s1 <= s2
s1.compare(s2)
s1.compare(pos, count, s2) // compare函数还有很多重载,编程时可查看文档选择最适合的
截取string的子串
str2 = str1.substr(pos); // 返回str1中从pos位置开始的子串
str2 = str1.substr(pos, count); // 返回str1中从pos开始的count个字符组成的子串
字符串连接
str1 + str2; // 返回新的字符串,其内容是str1和str2的连接
str + c_str; // string可以和c风格字符串c_str连接
c_str1 + c_str2 + str; // 编译错误:c_str1和c_str2不能直接相加,因为他们是char *型
str + c_str1 + c_str2; // 正确:str先加c_str1,其结果再加上c_str2。
向string后追加内容
// 1. 使用push_back
str.push_back(c); // 向str中追加一个字符
// 2. 使用append,append函数返回this索引,可以级联调用
str.append(...).append(...).append(...); // append函数有很多不同的重载,编程时可查看文档选择最适合的
// 3. 使用+=运算符
str += c; // 追加字符c
str += str2; // 追加一个string
str += c_str; // 追加一个c风格字符串
向string中插入内容
str.insert(...); // insert函数有很多重载,编程时可查看文档选择最合适的
从string中移除内容
str.pop_back(); // 移除尾部一个字符
str.erase(index); // 移除index后的全部字符,注意:是后面的全部字符
str.erase(index, 1); // 移除index位置的字符
str.erase(index, count); // 移除index后的count个字符
str.erase(pos_iter); // 移除迭代器iter后的全部字符,注意:仅移除一个字符
str.erase(first_iter, last_iter); // 移除迭代器范围[first_iter, last_iter)中的字符
str.clear(); // 清空
4. string的容量管理
// capacity函数返回string分配的存储容量
string::size_type cap = str.capacity();
// size和length函数功能一样,返回字符串的长度
string::size_type sz = str.size();
string::size_type len = str.length();
// max_size函数返回string中可存放的字符串的极限长度
string::size_type max_sz = str.max_size();
// reserve函数确保string中分配的容量超过某个值
str.reserver(new_cap);
// resize函数调整字符串的长度。
// 如果n超过原长度将会使用字符c填充,如果没有指定c那么使用0值填充。
// 如果n小于原长度,效果等价于去除尾部一些字符。
str.resize(n);
str.resize(n, c);
// shrink_to_fit函数请求移除未使用的容量。
// 这是减少 capacity() 到 size() 的非强制请求。是否满足请求取依赖于实现。
str.shrink_to_fit();
5. string中查找和替换
查找
// 1. find函数,本函数找到子串都会返回子串位置,找不到则返回string::npos。
// pos是str1中起始搜索的位置
str1.find(c, pos=0); // 在str1中查找字符c
str1.find(str2, pos=0); // 在str1中查找str2
str1.find(c_str1, pos=0); // 在str1中查找c风格字符串c_str1
str1.find(c_str1, pos, cnt); // 在str1中查找c分割字符串的子串[c_str1, c_str1+cnt)
// 2. rfind函数:反向查找,参数的定义与find函数一致
str1.rfind(c, pos=string::npos); // 在str1中反向查找字符c
str1.rfind(str2, pos=string::npos); // 在str1中反向查找str2
str1.rfind(c_str1, pos=string::npos); // 在str1中反向查找c风格字符串c_str1
str1.rfind(c_str1, posstring::npos, cnt); // 在str1中反向查找c分割字符串的子串[c_str1, c_str1+cnt)
// 3. find_first_of函数:
// find_first_of 函数最容易出错的地方是和find函数搞混。它最大的区别就是如果在一个字符串str1中查找另一个字符串str2,如果str1中含有str2中的任何字符,则就会查找成功,而find则不同;
size_type find_first_of ( const string& str, size_type pos = 0 ) const;
size_type find_first_of ( const char* s, size_type pos, size_type n ) const;
size_type find_first_of ( const char* s, size_type pos = 0 ) const;
size_type find_first_of ( char c, size_type pos = 0 ) const;
// 4. find_first_not_of函数:与find_fisrt_of恰好相反,查找的是this中未出现在目标str中的字符。
// 5. find_last_of函数:与find_fist_of相似但是反向查找
// 6. find_last_not_of函数:与find_last_of恰好相反,查找的是this中未出现在目标str中的字符。
替换
// 使用replace函数. 将[pos, pos+cnt)或[first, last)范围内的元素替换为目标字符串.
string& replace(size_type pos, size_type cnt,
const string& str);
string& replace(const_iterator first, const_iterator last,
const string& str);
string& replace(size_type pos, size_type cnt,
const string& str, size_type pos2, size_type cnt2=string::npos);
string& replace(const_iterator first, const_iterator last,
InputIt first2, InputIt last2);
string& replace(size_type pos, size_type cnt,
const char* cstr );
string& replace(size_type pos, size_type cnt,
const char* cstr, size_type cnt2);
string& replace( const_iterator first, const_iterator last,
const char* cstr );
string& replace(const_iterator first, const_iterator last,
const char* cstr, size_type cnt2);
// ... 还有一些重载,编程时可查看文档选择最合适的