🐱作者:傻响
🐱专栏:《C/C++ - STL》
🔥格言:你只管努力,剩下的交给时间!
目录
STD - String标准库
字符串类介绍
字符串类构造函数
No.1 string() ;
No.2 string(const char* s) ;
No.3 string(const string&s) ;
No.4 string(size_t n, char c);
No.5 string (const string& str, size_t pos, size_t len = npos);
No.6 string (const char* s, size_t n);
No.7 template <,class InputIterator> string (InputIterator first, InputIterator last);
string类对象的访问及遍历操作
No.1 operator[]
No.2 正向迭代器(iterator)
No.3 反向迭代器(reverse_iterator)
No.4 const迭代器
No.5 for范围
No.6 at
No.7 back
No.8 front
string类对象的容量操作
No.1 size() / length()
No.2 capacity()
No.3 max_size()
No.4 clear()
No.5 empty()
No.6 shrink_to_fit()
No.7 reserve()
No.8 resize ()
string类对象的修改操作
No.1 push_back()
No.2 append(push_back延申)
No.3 operator+=
No.4 Insert()
No.5 Erase()
No.6 assign()
No.7 replace()
No.8 find()
string类的模拟实现
STD - String标准库
string标准库是包含在STD库中。
链接: - C++ Reference (cplusplus.com)
// 声明 #include<string>
字符串类介绍
字符串是表示字符序列的对象。
标准字符串类通过与标准字节容器类似的接口提供对此类对象的支持,但添加了专门设计用于操作单字节字符字符串的特性。
string类是basic_string类模板的实例化,该模板使用char(即bytes)作为其字符类型,并具有默认的char_traits和allocator类型(有关模板的更多信息,请参阅basic_string)。
注意,这个类独立于所使用的编码处理字节:如果用于处理多字节或变长字符(如UTF-8)的序列,该类的所有成员(如length或size)及其迭代器仍将按照字节(而不是实际编码的字符)进行操作。
字符串类构造函数
构造函数名(constructor) | 功能说明 |
---|---|
string() ;(重点) | 空字符串构造函数(默认构造函数),构造一个空字符串,长度为零。 |
string(const char* s) ;(重点) | 从c字符串,复制由s指向的以空结束的字符序列(C-string)。 |
string(const string&s) ;(重点) | 拷贝构造函数,构造str的副本。 |
string(size_t n, char c);(一般) | 把构造函数 ,用字符c的n个连续副本填充字符串。 |
string (const string& str, size_t pos, size_t len = npos);(一般) | 子字符串构造函数 ,复制str中从字符位置pos开始并跨越len字符的部分(或者直到str的末尾,如果str太短,len很长,这样str有多少取多少,直到str结束)。 |
string (const char* s, size_t n);(一般) | 从缓冲区 ,从由s指向的字符数组中复制前n个字符。 |
template <class InputIterator> string (InputIterator first, InputIterator last);(一般) |
No.1 string() ;
空字符串构造函数(默认构造函数),构造一个空字符串,长度为零。
// 构造空字符串(默认构造函数)
string str1;
cout << str1 << endl;
No.2 string(const char* s) ;
从c字符串,复制由s指向的以空结束的字符序列(C-string)。
// 从c字符串,复制由s指向的以空结束的字符序列(C-string)。
string str2 = "傻响";
string str3 = "是啥";
cout << str2 << " " << str3 << endl;
No.3 string(const string&s) ;
拷贝构造函数,构造str的副本。
// 从c字符串,复制由s指向的以空结束的字符序列(C-string)。
string str2 = "傻响";
string str3 = "是啥";
cout << str2 << " " << str3 << endl;
// 拷贝构造函数,构造str副本。
string str4 = str2;
string str5(str3);
cout << str4 << " " << str5 << endl;
No.4 string(size_t n, char c);
把构造函数 ,用字符c的n个连续副本填充字符串。
// 把构造函数 ,用字符c的n个连续副本填充字符串。
string str6(10, '*');
cout << str6 << endl;
No.5 string (const string& str, size_t pos, size_t len = npos);
子字符串构造函数 ,复制str中从字符位置pos开始并跨越len字符的部分(或者直到str的末尾,如果str太短,len很长,这样str有多少取多少,直到str结束)。
// 从缓冲区 ,从由s指向的字符数组中复制前n个字符。
string str7("Hello World", 5);
cout << str7 << endl;
No.6 string (const char* s, size_t n);
从缓冲区 ,从由s指向的字符数组中复制前n个字符。
// 从缓冲区 ,从由s指向的字符数组中复制前n个字符。
string str7("Hello World", 5);
cout << str7 << endl;
// 子字符串构造函数 ,复制str中从字符位置pos开始并跨越len字符的部分(或者直到str的末尾,如果str太短或len为string::npos)。
string str8(str7, 2, 3);
cout << str8 << endl;
No.7 template <,class InputIterator> string (InputIterator first, InputIterator last);
string类对象的访问及遍历操作
函数名称 | 功能说明 |
---|---|
operator[] (重点) | 返回pos位置的字符,const string类对象调用 |
begin+ end | begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭 代器 |
rbegin + rend | begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭 代器 |
范围for | C++11支持更简洁的范围for的新遍历方式 |
No.1 operator[]
返回对字符串中位置为pos的字符的引用。
char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;
// pos:
// 值与字符在字符串中的位置一起。
// 注意:字符串中的第一个字符用值0表示(而不是1)。
// Size_t是无符号整型(与成员类型string::size_type相同)。
// 返回值:
// 位于字符串中指定位置的字符。
// 如果字符串对象是const限定的,则该函数返回const char&。否则,它返回char&。
string str1("1234");
cout << str1 << endl;
// 使用operator[]运算符重载的方式进行对字符串的每个字符加1。
for (size_t i = 0; i < str1.size(); i++)
{
str1[i]++;
}
cout << str1 << endl;
No.2 正向迭代器(iterator)
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
string str1("2345");
cout << str1 << endl;
// 迭代器(iterator):行为上像指针一样的类型。
string::iterator it = str1.begin(); // begin指向string第一个位置。
while (it != str1.end()) // end指向string最后一个字符的下一个位置。
{
*it += 1;
++it;
}
// 迭代器打印
it = str1.begin();
while (it != str1.end())
{
cout << *it;
++it;
}
cout << endl;
No.3 反向迭代器(reverse_iterator)
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;
string str1 = "1234";
cout << str1 << endl;
// 迭代器(reverse_iterator):行为上像指针一样的类型。
string::reverse_iterator rit = str1.rbegin();
while (rit != str1.rend())
{
cout << *rit;
rit++;
}
cout << endl;
No.4 const迭代器
这里演示一下const iterator。
void Print(const string& s)
{
// 遍历string const::interator只能读,不支持写
string::const_iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
string::const_reverse_iterator rit = s.rbegin();
while (rit != s.rend())
{
cout << *rit << " ";
++rit;
}
cout << endl;
}
int main()
{
string str1 = "1234";
cout << str1 << endl;
// 测试const迭代器
Print(str1);
}
No.5 for范围
string str1("2345");
cout << str1 << endl;
// 使用for范围
for (auto& ch : str1)
{
ch--;
}
cout << str1 << endl;
No.6 at
返回对字符串中位置为pos的字符的引用.
该函数自动检查pos是否是字符串中某个字符的有效位置(即pos是否小于字符串长度),如果不是则抛出out_of_range异常。
string str1 = "Hello World";
// 使用at进行打印。
for (size_t i = 0; i < str1.size(); i++)
{
cout << str1.at(i);
}
cout << endl;
No.7 back
返回对字符串最后一个字符的引用。
此函数不能在空字符串上调用。
char& back();
const char& back() const;
string str1 = "Hello World";
// 返回str1中最后一个字符。
char lastChar = str1.back();
No.8 front
返回对字符串第一个字符的引用。
与返回指向相同字符的迭代器的member string::begin不同,此函数返回直接引用。
此函数不能在空字符串上调用。
char& front();
const char& front() const;
string str1 = "Hello World";
// 返回str1中第一个字符。
char firstChar = str1.front();
string类对象的容量操作
函数名称 | 功能说明 |
---|---|
size(重点) | 返回字符串有效字符长度 |
length | 返回字符串有效字符长度 |
capacity | 返回空间总大小 |
empty (重点) | 检测字符串释放为空串,是返回true,否则返回false |
clear (重点) | 清空有效字符 |
reserve (重点) | 为字符串预留空间 |
resize (重点) | 将有效字符的个数该成n个,多出的空间用字符c填充 |
max_size | 返回字符串的最大大小 |
shrink_to_fit | 缩小以适应,请求字符串减少其容量以适应其大小。 |
No.1 size() / length()
返回字符串的长度,以字节为单位。
这是符合字符串内容的实际字节数,它不一定等于其存储容量。
注意,字符串对象处理字节时不知道最终可能用于编码其包含的字符的编码。因此,返回的值可能与多字节或变长字符序列(如UTF-8)中编码字符的实际数量不对应。
string::size和string::length都是同义词,返回相同的值。
size_t size() const;
size_t length() const;
string str1 = "Hello World";
// 使用Stirng::size / String::lenght
cout << str1.size() << " " << str1.length() << endl;
No.2 capacity()
返回当前分配给字符串的存储空间大小,以字节表示。
这个容量不一定等于字符串长度。它可以等于或更大,额外的空间允许对象在向字符串中添加新字符时优化其操作。
注意,此容量并不假设对字符串的长度有限制。当此容量耗尽且需要更多时,对象会自动扩展该容量(为其重新分配存储空间)。字符串长度的理论限制由成员max_size给出。
在修改对象的任何时候,都可以更改字符串的容量,即使这种修改意味着大小的减少或容量尚未耗尽(这与vector容器中提供的容量保证相反)。
字符串的容量可以通过调用成员预留显式更改。
size_t capacity() const;
string str1 = "Hello World";
string str2 = "Hello";
// 使用string::capacity
cout << str1.capacity() << endl;
cout << str2.capacity() << endl;
No.3 max_size()
返回字符串可以达到的最大长度。
这是由于已知的系统或库实现限制,字符串可以达到的最大潜在长度,但不能保证对象能够达到该长度:在达到该长度之前,它仍然可能无法分配存储。
size_t max_size() const;
string str1 = "Hello World";
string str2 = "Hello";
// 使用string::max_size()
cout << str1.max_size() << endl;
cout << str2.max_size() << endl;
No.4 clear()
擦除字符串的内容,使其成为空字符串(长度为0个字符)。
void clear();
string str1 = "Hello World";
string str2 = "Hello";
// 使用string::clear()
str2.clear();
cout << str2 << endl;
cout << str2.capacity() << endl;
No.5 empty()
返回字符串是否为空(即其长度是否为0)。
此函数不以任何方式修改字符串的值。要清除字符串的内容,请参见string::clear。
bool empty() const;
string str1 = "Hello World";
string str2 = "Hello";
// 使用string::clear()
str2.clear();
cout << str2 << endl;
cout << str2.capacity() << endl;
// 使用string::empty()
cout << boolalpha << str1.empty() << endl; // false
cout << boolalpha << str2.empty() << endl; // true
No.6 shrink_to_fit()
请求字符串减少其容量以适应其大小。
该请求是非绑定的,容器实现可以自由优化,使字符串的容量大于其大小。
此函数对字符串长度没有影响,也不能更改其内容。
void shrink_to_fit();
string str1(100,'x');
string str2(200, 'x');
cout << "str1的大小" << str1.size() << endl;
cout << "str2的大小" << str2.size() << endl;
cout << "str1的容量:" << str1.capacity() << endl;
cout << "str2的容量:" << str2.capacity() << endl;
str1.resize(10);
str2.resize(20);
// 调用str1和str2的shrink_to_fit()函数自适应调整大小。
str1.shrink_to_fit();
str2.shrink_to_fit();
cout << "str1的大小" << str1.size() << endl;
cout << "str2的大小" << str2.size() << endl;
cout << "str1的容量:" << str1.capacity() << endl;
cout << "str2的容量:" << str2.capacity() << endl;
No.7 reserve()
请求调整字符串容量,以适应计划的大小更改,长度最多为n个字符。
如果n大于当前字符串容量,则该函数将容器的容量增加到n个字符(或更大)。
在所有其他情况下,收缩字符串容量都被视为非绑定请求:容器实现可以自由优化,否则将使字符串的容量大于n。
此函数对字符串长度没有影响,也不能更改其内容。
void reserve (size_t n = 0);
string str1 = "Hello World";
cout << str1.size() << endl;
cout << str1.capacity() << endl;
cout << str1 << endl << endl;
// 调用reserbe()函数进行预备空间。
str1.reserve(1000);
cout << str1.size() << endl;
cout << str1.capacity() << endl;
cout << str1 << endl;
No.8 resize ()
将字符串的长度调整为n个字符。
如果n小于当前字符串长度,则将当前值缩短为第n个字符,删除第n个字符以外的字符。
如果n大于当前字符串长度,则通过在末尾插入所需的字符来扩展当前内容,以达到n的大小。如果指定了c,则将新元素初始化为c的副本,否则,它们是值初始化的字符(空字符)。
void resize (size_t n);
void resize (size_t n, char c);
// resize源数据相当于删除。
string str1 = "Hello World";
str1.resize(5);
cout << str1.size() << endl;
cout << str1.capacity() << endl;
cout << str1 << endl << endl;
// resize源数据不变,后面追加\0
string str2 = "Hello World";
str2.resize(20);
cout << str2.size() << endl;
cout << str2.capacity() << endl;
cout << str2 << endl << endl;
// resize元数据改变,后面追加了x
string str3 = "Hello World";
str3.resize(20,'x');
cout << str3.size() << endl;
cout << str3.capacity() << endl;
cout << str3 << endl << endl;
string类对象的修改操作
函数名称 | 功能说明 |
---|---|
push_back | 在字符串后尾插字符c |
append | 在字符串后追加一个字符串 |
operator+= (重点) | 在字符串后追加字符串str |
c_str(重点) | 返回C格式字符串 |
find + npos(重点) | 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 |
rfind | 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置 |
substr | 在str中从pos位置开始,截取n个字符,然后将其返回 |
No.1 push_back()
将字符附加到字符串
将字符c追加到字符串的末尾,使其长度增加1。
// push_back();单个字符进行push
string str1 = "Hello World";
str1.push_back('!');
str1.push_back('-');
cout << str1 << endl;
No.2 append(push_back延申)
string& append (const string& str);
string& append (const string& str, size_t subpos, size_t sublen);
string& append (const char* s);
string& append (const char* s, size_t n);
string& append (size_t n, char c);
template <class InputIterator>
string& append (InputIterator first, InputIterator last);
(1)字符串:追加str的副本。
(2)子串 :追加str的子字符串的副本。该子字符串是str中从字符位置subpos开始并跨越子字符的部分(或者直到str的末尾,如果str太短或如果sublen是string::npos)。
(3) c字符串:追加由由s指向的以空结束的字符序列(C-string)组成的字符串的副本。
(4)缓冲区:追加由s指向的字符数组中前n个字符的副本。
(5)填:追加字符c的n个连续拷贝。
(6)范围:以相同的顺序追加范围[第一个,最后一个)中的字符序列的副本。
(7)初始化器列表:以相同的顺序追加il中每个字符的副本。
// push_back();单个字符进行push
string str1 = "Hello World";
str1.push_back('!');
str1.push_back('-');
cout << str1 << endl;
cout << endl;
// append作为push_back的延申,可追加字符串。
str1.append("ShaXiang");
cout << str1 << endl;
No.3 operator+=
string& operator+= (const string& str);
string& operator+= (const char* s);
string& operator+= (char c);
// str:字符串对象,其值在末尾被复制。
// s:指向以空结束的字符序列的指针。在字符串的末尾复制序列。
// c:一个字符,被附加到字符串的当前值之后。
// il:一个initializer_list对象。这些对象是由初始化器列表声明符自动构造的。字符以相同的顺序被追加到字符串中。
// 返回值:*this
str1 += "886";
cout << str1 << endl;
No.4 Insert()
string插入接口,这里我就举例一个,其他接口可以登录链接自行查看。
// 插入str的副本。
string& insert (size_t pos, const string& str);
// pos:插入点:新内容插入到字符的前面,位置为pos,注意:第一个字符用值0表示(而不是1)。
// str:另一个字符串对象。
string s("Hello world");
cout << s << endl;
// string::Insert插入函数。
s.insert(0, "ShaXiang");
cout << s << endl;
s.insert(5, "ShaXiang");
cout << s << endl;
No.5 Erase()
删除字符串的一部分,减少其长度:
string& erase (size_t pos = 0, size_t len = npos);
// pos:第一个要擦除的字符的位置,注意:str中的第一个字符用值0表示(而不是1)。
// len:要删除的字符数(如果字符串较短,则删除尽可能多的字符)。
string s("Hello world");
cout << s << endl;
// string::Erase删除函数。
s.erase(0, 5);
cout << s << endl;
s.erase(2);
cout << s << endl;
// 结果:
Hello world
world
w
No.6 assign()
将新值赋给字符串,替换其当前内容。
string& assign (const string& str);
string& assign (const char* s, size_t n);
No.7 replace()
将字符串中以字符pos开始并跨越len字符的部分(或字符串中[i1,i2)之间的部分)替换为新内容:
string& replace (size_t pos, size_t len, const string& str);
No.8 find()
在字符串中搜索由其参数指定的序列的第一个出现项。
当指定pos时,搜索只包括位置pos上或之后的字符,忽略任何可能出现的包括pos之前的字符。
注意,与成员find_first_of不同的是,每当搜索多个字符时,只匹配其中一个字符是不够的,而必须匹配整个序列。
size_t find (const string& str, size_t pos = 0) const;
// str:另一个带有要搜索的主题的字符串。
// pos:要在搜索中考虑的字符串中第一个字符的位置。如果该值大于字符串长度,则函数永远找不到匹配项。
// 注意:第一个字符用值0表示(而不是1):值0表示搜索整个字符串。
// 返回值:第一个匹配的第一个字符的位置。如果没有找到匹配项,函数返回string::npos。Size_t是无符号整型(与成员类型string::size_type相同)。
string类的模拟实现
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<assert.h>
using namespace std;
namespace ShaXiang
{
class string
{
public:
// 构造函数:带参构造。
string(const char* str)
{
_size = strlen(str);
_capacity = _size;
_str = new char [strlen(str) + 1];
// C语言的字符串拷贝函数。
strcpy(_str, str);
}
// 构造函数:无参数构造。
string()
{
_str = new char[1];
_str[0] = '\0';
_capacity = _size = 0;
}
// 拷贝构造函数 - 传统写法。
//string(const string& s)
//{
// _str = new char[s._capacity + 1];
// _capacity = s._capacity;
// _size = s._size;
// strcpy(_str, s._str);
//}
// 拷贝构造函数 - 现在写法。
string(const string& s)
:_str(nullptr)
,_size(0)
,_capacity(0)
{
string temp(s._str);
swap(temp);
}
// 析构函数。
~string()
{
delete[] _str;
_str = nullptr;
_capacity = _size = 0;
}
// 迭代器。
typedef char* iterator;
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
// 交换
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
// 扩容。
void reserve(size_t n)
{
if (_capacity < n)
{
char* pTemp = new char[n + 1];
strcpy(pTemp, _str);
delete[] _str;
_str = pTemp;
_capacity = n;
}
}
void resize(size_t n, char ch = '\0')
{
if (n > _size)
{
reserve(n);
for (size_t i = _size; i < n; ++i)
{
_str[i] = ch;
}
_size = n;
_str[_size] = '\0';
}
else
{
_str[n] = '\0';
_size = n;
}
}
// 尾插入一个字符。
void push_back(char ch)
{
// 检查是否需要扩容。
if (_size == _capacity)
{
// 判断首次开辟内存空间。
size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;
reserve(newCapacity); // 扩容。
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';
}
// 尾插入一个字符串。
void append(const char* str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
strcpy(_str + _size, str);
_size += len;
}
// 在pos位置插入一个字符
string& insert(size_t pos, char ch)
{
if (_size == _capacity)
{
size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;
reserve(newCapacity);
}
// 先挪动数据(注意挪动数据\还有整型提升的问题)
size_t end = _size + 1;
while (end > pos)
{
_str[end] = _str[end - 1];
--end;
}
_str[pos] = ch;
++_size;
return *this;
}
// 在pos位置插入字符串。
string& insert(size_t pos, const char* str)
{
// 求字符串个数,进行扩容。
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
// 挪动数据
size_t end = _size + len;
while (end >= pos + len)
{
_str[end] = _str[end - len];
--end;
}
// 拷贝整个要插入的字符串,到移动出来的空位置。
// No.1
/*const char* begin = str;
size_t i = pos;
while (*begin != '\0')
{
_str[i] = *begin;
++i;
++begin;
}*/
// No.2
strncpy(_str + pos, str, len);
_size += len;
return *this;
}
string& erase(size_t pos, size_t len = npos)
{
assert(pos < _size);
if (len == npos || pos + len > _size)
{
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str + pos, _str + pos + len);
_size -= len;
}
return *this;
}
size_t find(const char ch, size_t pos = 0) const
{
assert(pos < _size);
while (pos < _size)
{
if (_str[pos] == ch)
{
return pos;
}
++pos;
}
return npos;
}
size_t find(const char* str, size_t pos = 0) const
{
assert(pos < _size);
const char* result = strstr(_str + pos, str);
if (result == nullptr)
{
return npos;
}
else
{
return result - _str;
}
}
// 返回字符串指针。
const char* c_str() const
{
return _str;
}
// 返回字符串大小。
size_t size() const
{
return _size;
}
size_t capacity() const
{
return _capacity;
}
// 返回_str每一个元素的值。
char& operator[](size_t pos)
{
// 检查pos是否越界。
assert(pos < _size);
// 返回_str每一个元素的值。
return _str[pos];
}
const char& operator[](size_t pos) const
{
// 检查pos是否越界。
assert(pos < _size);
// 返回_str每一个元素的值。
return _str[pos];
}
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
string& operator+=(const char* str)
{
append(str);
return *this;
}
//string& operator=(const string& s)
//{
// if (this != &s)
// {
// char* tmp = new char[s._capacity + 1];
// strcpy(tmp, s._str);
// delete[] _str;
// _str = tmp;
// _size = s._size;
// _capacity = s._capacity;
// }
// return *this;
//}
string& operator=(string s)
{
swap(s);
return *this;
}
void clear()
{
_size = 0;
_str[_size] = '\0';
}
private:
char* _str;
size_t _size;
size_t _capacity;
const static size_t npos = -1;
};
// 字符串输出流
inline ostream& operator<<(ostream& out, const string& s)
{
for (size_t i = 0; i < s.size(); ++i)
{
out << s[i];
}
return out;
}
// 字符串输入流
inline istream& operator>>(istream& in, string& s)
{
//char ch = in.get();
//while (ch != ' ' && ch != '\n')
//{
// s += ch;
// ch = in.get();
//}
s.clear();
char buffer[128] = { '\0' };
size_t i = 0;
char ch = in.get();
while (ch != ' ' && ch != '\n')
{
if (i == 127)
{
// 满了
s += buffer;
i = 0;
}
buffer[i++] = ch;
ch = in.get();
}
if (i > 0)
{
buffer[i] = '\0';
s += buffer;
}
return in;
}
//istream& operator>>(istream& in, string& s)
//{
// return in;
//}
}