前言
- 将对string_view称呼为sv
1 string_view概述
sv对象不拥有数据,只是对数据的引用。因此,对sv对象有两点限制:
- 不允许修改sv对象内部的数据
- sv对象引用的数据要有足够长的生命周期
string_view类只声明了两个私有成员,如下:
size_t _M_len; //字符串的长度,不一定是strlen(_M_str)
const _CharT* _M_str; //对字符串的引用,通过指针去访问,并没有开辟一个新的数组
2 string_view使用
1 constructor
- 无参构造
constexpr
basic_string_view() noexcept
: _M_len{0}, _M_str{nullptr}
{ }
- 使用字符串字面量构造
注意:字符串中间插入null字符,会对字符串进行截取
__attribute__((__nonnull__)) constexpr
basic_string_view(const _CharT* __str) noexcept
: _M_len{traits_type::length(__str)},
_M_str{__str}
- 使用字符串字面量 + 指定长度构造
注意:可以解决这个问题
constexpr
basic_string_view(const _CharT* __str, size_type __len) noexcept
: _M_len{__len}, _M_str{__str}
{ }
- 使用迭代区间构造
注意:to_address
内部有一个静态断言,如果_first为函数指针,会发生错误
constexpr
basic_string_view(_It __first, _End __last)
noexcept(noexcept(__last - __first))
: _M_len(__last - __first), _M_str(std::to_address(__first))
{ }
2 remove_prefix, remove_suffix
移除指定长度的前缀和后缀
constexpr void
remove_prefix(size_type __n) noexcept
{
__glibcxx_assert(this->_M_len >= __n);
this->_M_str += __n;
this->_M_len -= __n;
}
constexpr void
remove_suffix(size_type __n) noexcept
{ this->_M_len -= __n; }
3 copy
从sv对象引用字符串的__pos位置开始,拷贝n个字符到__str字符数组中,返回实际拷贝的字符数
注意:由于标准库内部做了优化操作,如果你想拷贝从某个字符起始的所有字符,__n可以取最大
size_type
copy(_CharT* __str, size_type __n, size_type __pos = 0) const
{
__glibcxx_requires_string_len(__str, __n); // 要求__str字符数组的长度大于等于__n
__pos = std::__sv_check(size(), __pos, "basic_string_view::copy"); //检查sv对象中__pos位置是否存在,也就是比较size()和__pos的大小
const size_type __rlen = std::min(__n, _M_len - __pos); //要拷贝字符的个数。标准库内部的优化操作,防止拷贝是越界
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2777. basic_string_view::copy should use char_traits::copy
traits_type::copy(__str, data() + __pos, __rlen);
return __rlen;
}
4 substr
获取从某个位置起始,指定长度的,string_view对象
constexpr basic_string_view
substr(size_type __pos = 0, size_type __n = npos) const noexcept(false)
{ //npos 是unsigned long类型,值为-1,也就是数值最大
__pos = std::__sv_check(size(), __pos, "basic_string_view::substr");
const size_type __rlen = std::min(__n, _M_len - __pos);
return basic_string_view{_M_str + __pos, __rlen};
}
5 starts_with, ends_with
1 starts_with
检查sv对象是否以某一个字符或字符串为前缀
constexpr bool
starts_with(basic_string_view __x) const noexcept
{ return this->substr(0, __x.size()) == __x; }
constexpr bool
starts_with(_CharT __x) const noexcept
{ return !this->empty() && traits_type::eq(this->front(), __x); }
constexpr bool
starts_with(const _CharT* __x) const noexcept
{ return this->starts_with(basic_string_view(__x)); }
2 ends_with
检查sv对象是否以某一个字符或字符串为后缀
constexpr bool
ends_with(basic_string_view __x) const noexcept
{
const auto __len = this->size();
const auto __xlen = __x.size();
return __len >= __xlen
&& traits_type::compare(end() - __xlen, __x.data(), __xlen) == 0;
}
constexpr bool
ends_with(_CharT __x) const noexcept
{ return !this->empty() && traits_type::eq(this->back(), __x); }
constexpr bool
ends_with(const _CharT* __x) const noexcept
{ return this->ends_with(basic_string_view(__x)); }
6 find和rfind
在sv对象中查找某一个字符或字符串
说明:__pos
是sv对象内查找的起始位置,__str
目标字符串,__c
查找的字符,__n
目标字符串的长度
constexpr size_type
find(basic_string_view __str, size_type __pos = 0) const noexcept
{ return this->find(__str._M_str, __pos, __str._M_len); }
constexpr size_type
find(_CharT __c, size_type __pos = 0) const noexcept;
constexpr size_type
find(const _CharT* __str, size_type __pos, size_type __n) const noexcept;
__attribute__((__nonnull__)) constexpr size_type
find(const _CharT* __str, size_type __pos = 0) const noexcept
{ return this->find(__str, __pos, traits_type::length(__str));
rfind类似,不做解释
7 find_first_of, find_last_of, find_first_not_of, find_last_not_of
这里解释第一个find_first_of。在源字符串视图中,目标字符串字符集合中字符出现的第一个位置
参数和find类似
constexpr size_type
find_first_of(basic_string_view __str, size_type __pos = 0) const noexcept
{ return this->find_first_of(__str._M_str, __pos, __str._M_len); }
constexpr size_type
find_first_of(_CharT __c, size_type __pos = 0) const noexcept
{ return this->find(__c, __pos); }
constexpr size_type
find_first_of(const _CharT* __str, size_type __pos,
size_type __n) const noexcept;
__attribute__((__nonnull__)) constexpr size_type
find_first_of(const _CharT* __str, size_type __pos = 0) const noexcept
{ return this->find_first_of(__str, __pos, traits_type::length(__str)); }
其他类似
8 对sv对象的比较
- 使用简单的比较运算符
- sv类重载了三路运算符,使用三路运算符比较
- 使用compare成员函数比较
1 简单比较运算符
std::string_view strView = "world!";
std::string_view charsToExclude = "world!";
if (strView < charsToExclude) std::cout << "小于" << std::endl;
else if (strView > charsToExclude) std::cout << "大于" << std::endl;
else if (strView == charsToExclude) std::cout << "等于" << std::endl;
2 三路运算符
auto result = strView <=> charsToExclude;
if (std::is_lt(result)) std::cout << "小于" << std::endl;
else if (result == std::partial_ordering::greater) std::cout << "大于" << std::endl;
else if (result == std::partial_ordering::equivalent) std::cout << "等于" << std::endl;
3 compare
int res = strView.compare(charsToExclude);
if (res < 0) std::cout << "小于" << std::endl;
else if (res > 0) std::cout << "大于" << std::endl;
else if (res == 0) std::cout << "等于" << std::endl;
其他简单方法
1 size,length
获取引用字符串的长度
constexpr size_type
size() const noexcept
{ return this->_M_len; }
constexpr size_type
length() const noexcept
{ return _M_len; }
2 empty
判断是否为空
[[nodiscard]] constexpr bool
empty() const noexcept
{ return this->_M_len == 0; }