C++中对于字符串的处理进行了特殊的封装,使得这个容器既具有普通容器的性质,又能对于字符串进行处理。
下面对一些常用的string接口进行说明。
1.构造函数
首先来看string的构造函数。
string()//构造空的string类对象
string(const char* s) //利用C-string来构造类对象
string(const string& s)//拷贝构造
2.常用容量操作
size_t size() const;//返回字符串的有效长度
bool empty() const;//判断字符串是否为空
void clear();//清空有效字符串
void reserve (size_t n = 0);//为字符串申请空间
//resize构成函数重载,申请空间将多余的空间初始化为c
void resize (size_t n);
void resize (size_t n, char c);
(1)这里值得一提的是size()和length ()底层实现是一样的,但是实现size()出现的原因是为了和其他容器保持一致。一般而言使用size()。
(2)clear只清楚内容,不会清楚底层空间。
3.string类对象的访问
char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;
//string中重载了[]使得能够像数组一样访问元素
iterator begin();
const_iterator begin() const;
//string中定义了begin函数返回字符串首个字符的迭代器,在这里可以认为是指针
iterator end();
const_iterator end() const;
//end()与begin()相反end是返回最后一个元素的迭代器
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
//反向迭代器,rbegin()就是返回最后一个元素的迭代器
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
//反向迭代器,rend()就是返回第一个元素的迭代器
4.string常用修改操作
void push_back (char c);//字符串尾插字符
//重载+=能够在尾部添加字符
string& operator+= (const string& str);
string& operator+= (const char* s);
string& operator+= (char c);
//返回一个C格式的字符串
const char* c_str() const noexcept;
//从pos位置开始返回长度为len个字符
//这里的npos是一个静态成员变量,可以理解为字符串的末尾
string substr (size_t pos = 0, size_t len = npos) const;
5.string类的非成员函数
//流插入
istream& operator>> (istream& is, string& str);
//流提取
istream& operator<< (istream& is, string& str);
//获取一行字符串
istream& getline (istream& is, string& str, char delim);
istream& getline (istream& is, string& str);
最后可以大致模拟实现一个string容器
class string
{
public:
//这里定义string的正向迭代器
//对于string来说,迭代器就可以看作是指针
//const迭代器也是如此
typedef char* iterator;
typedef const char* const_iterator;
iterator begin() { return _str; }//返回头指针
const_iterator begin() const { return _str; }//返回const头指针
iterator end() { return _str + _size; }//返回尾指针
const_iterator end() const { return _str + _size; }//返回const尾指针
//构造函数,这里初始化列表构造直接深拷贝
string(const char* str = "")
: _size(strlen(str))
, _capacity(_size)
, _str(new char[_capacity + 1])
{
memcpy(_str, str, _size + 1);
}
//拷贝构造
string(const string& s)
: _size(s._size)
, _capacity(s._capacity)
, _str(new char[_capacity + 1])
{
memcpy(_str, s._str, _size + 1);
}
void swap(string& s)
{
std::swap(_str, s._str);//交换两个字符串头指针的指向
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
//这里是传统写法进行赋值重载
//string& operator=(const string& s)
//{
// if (this != &s)//不是自己给自己赋值
// {
// //char* temp = new char[s._capacity + 1];//先开空间,拷贝,然后旧的空间可以释放,在指向新的空间
// //memcpy(temp, s._str, s._size);
// //delete[] _str;
// //_str = temp;//首元素地址
// //_size = s._size;
// //_capacity = s._capacity;
// string temp(s);//调用拷贝构造
// //std::swap(_str, temp._str);//交换两个字符串头指针的指向
// //std::swap(_size, temp._size);
// //std::swap(_capacity, temp._capacity);
// //this->swap(temp)
// swap(temp);
// }
// return *this;
//}
//现代写法进行赋值重载
//传引用返回,如果不传引用this生命周期结束就销毁
string& operator=(string& s)
{
swap(s);
return *this;
}
~string()
{
delete[] _str;
}
//转换为C格式的字符
const char* c_str() const { return _str; }
//返回当前字符串大小
size_t size() const { return _size; }
//[]重载和const[]重载
char& operator[](size_t pos) { assert(pos < _size); return _str[pos]; }
const char& operator[](size_t pos) const { assert(pos < _size); return _str[pos];}
//开辟空间,扩容
void reserve(size_t n)
{
if (n > _capacity)
{
char* temp = new char[n + 1];
memcpy(temp, _str, _size + 1);
delete[] _str;
_str = temp;
_capacity = n;
}
}
//开辟空间初始化,可以复用reserve()
void resize(size_t n, char c = '\0')
{
if (_size > n)
{
_size = n;
_str[_size] = '\0';
}
else
{
reserve(n);
for (size_t i = _size; i < n; i++)
{
_str[i] = c;
}
_size = n;
_str[_size] = '\0';
}
}
//尾插一个字符,需要注意的是末尾的\0
void push_back(char ch)
{
if (_size == _capacity)
{
size_t new_capacity = _capacity == 0 ? 4 : _capacity * 2;
reserve(new_capacity);
}
_str[_size] = ch;
_size++;
_str[_size] = '\0';
}
//在字符串后面追加一个字符串
//这里需要注意扩容
void append(const char* str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
memcpy(_str + _size, str, len + 1);
_size += len;
}
//+=重载,可以复用push_back()
//这里是添加一个字符
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
//+=重载,可以复用append()
//这里是添加一个字符串
string& operator+=(const char* str)
{
append(str);
return *this;
}
//在pos位置插入n个数据,这里需要注意移动数据
void insert(size_t pos, size_t n, char ch)
{
assert(pos <= _size);
if (_size + n > _capacity)
{
reserve(_size + n);
}
size_t end = _size;
while (end >= pos)
{
_str[end + n] = _str[end];
end--;
}
for (size_t i = 0; i < n; i++)
{
_str[pos + i] = ch;
}
_size += n;
_str[_size] = '\0';
}
//在pos位置插入字符串
void insert(size_t pos, const char* str)
{
assert(pos <= _size);
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
size_t end = _size;
while (end >= pos)
{
_str[end + len] = _str[end];
end--;
}
memcpy(_str + pos, str, len);
_size += len;
_str[_size] = '\0';
}
//从pos位置开始删除len长度的字符
void erase(size_t pos, size_t len = npos)
{
assert(pos <= _size);
if (len == npos || pos + len >= _size)
{
_str[pos] = '\0';
_size = pos;
}
else
{
size_t end = pos + len;
while (end < _size)
{
_str[pos++] = _str[end++];
}
_size -= len;
_str[_size] = '\0';
}
}
//查找pos位置的字符
size_t find(char ch, size_t pos = 0)
{
assert(pos <= _size);
for (size_t i = pos; i < _size; i++)
{
if (_str[i] == ch)
{
return i;
}
}
return npos;
}
//查找字符串,这里可以使用C语言中的strstr()查找子串
size_t find(const char* str, size_t pos = 0)
{
assert(pos <= _size);
const char* ptr = strstr(_str + pos, str);
if (ptr)
{
return ptr - _str;
}
return npos;
}
//从pos位置开始截取len长度的字符串
string substr(size_t pos = 0, size_t len = npos)
{
size_t n = len;
if (len == npos || pos + len > _size)
{
n = _size - pos;
}
string temp;
temp.reserve(n);
memcpy(temp._str, _str + pos, n);
temp._size = n;
temp._str[n] = '\0';
return temp;
}
//清除内容
void clear()
{
_size = 0;
_str[0] = '\0';
}
//这里可以直接使用C语言中的memcmp()
bool operator<(const string s) const
{
//size_t i1 = 0;
//size_t i2 = 0;
//while (i1 < _size && i2 < s._size)
//{
// if (_str[i1] < s._str[i2])
// {
// return true;
// }
// else if (_str[i1] > s._str[i2])
// {
// return false;
// }
// else
// {
// ++i1;
// ++i2;
// }
//}
//if (i1 == _size && i2 != s._size)
//{
// return true;
//}
//else
//{
// return false;
//}
//hello hello --false
//helloxx hello --- fasle
//hello helloxx --- true
bool ret = memcmp(_str, s._str, _size < s._size ? _size : s._size);//按照长度小的进行比较
return ret == 0 ? _size < s._size : ret < 0;
}
//这里也是使用C语言的memcmp()
bool operator==(const string& s) const
{
return _size == s._size && memcmp(_str, s._str, _size) == 0;
}
//下面的运算符重载可以直接复用上面的两个重载即可
bool operator<=(const string& s) const
{
return *this < s || *this == s;
}
bool operator>(const string& s) const
{
return !(*this <= s);
}
bool operator>=(const string& s) const
{
return !(*this < s);
}
bool operator!=(const string& s) const
{
return !(*this == s);
}
private:
size_t _size;//当前string中有多少个元素
size_t _capacity;//空间
char* _str;
static const size_t npos;
};
const size_t string::npos = -1;
// 重载流插入运算符
std::ostream& operator<<(std::ostream& out, const string& s)
{
for (size_t i = 0; i < s.size(); i++)
{
out << s[i];
}
return out;
}
// 重载流提取运算符
std::istream& operator>>(std::istream& in, string& s)
{
s.clear();
char ch;
while (in.get(ch) && !isspace(ch))
{
s.push_back(ch);
}
return in;
}