96、C++ 字符串处理与视图类详解

C++ 字符串处理与视图类详解

1. 字符串元素擦除函数

在 C++ 中,提供了一个用于擦除字符串中满足特定条件元素的函数模板:

template <class charT, class traits, class Allocator, class Predicate>
void erase_if(basic_string<charT, traits, Allocator>& c, Predicate pred);

其效果等同于:

c.erase(remove_if(c.begin(), c.end(), pred), c.end());
2. 数值转换函数
2.1 字符串转整数

以下是一系列将字符串转换为整数的函数:

int stoi(const string& str, size_t* idx = nullptr, int base = 10);
long stol(const string& str, size_t* idx = nullptr, int base = 10);
unsigned long stoul(const string& str, size_t* idx = nullptr, int base = 10);
long long stoll(const string& str, size_t* idx = nullptr, int base = 10);
unsigned long long stoull(const string& str, size_t* idx = nullptr, int base = 10);
  • 效果 :前两个函数调用 strtol(str.c_str(), ptr, base) ,后三个函数分别调用 strtoul(str.c_str(), ptr, base) strtoll(str.c_str(), ptr, base) strtoull(str.c_str(), ptr, base) 。若函数不抛出异常且 idx != 0 ,则会将 str 中第一个未转换元素的索引存储在 *idx 中。
  • 返回值 :转换后的结果。
  • 异常抛出 :若 strtol strtoul strtoll strtoull 报告无法进行转换,则抛出 invalid_argument 异常;若转换值超出返回类型的可表示范围,或 strtol strtoul strtoll strtoull errno 设置为 ERANGE ,则抛出 out_of_range 异常。
2.2 字符串转浮点数
float stof(const string& str, size_t* idx = nullptr);
double stod(const string& str, size_t* idx = nullptr);
long double stold(const string& str, size_t* idx = nullptr);
  • 效果 :这些函数分别调用 strtof(str.c_str(), ptr) strtod(str.c_str(), ptr) strtold(str.c_str(), ptr) 。若函数不抛出异常且 idx != 0 ,则会将 str 中第一个未转换元素的索引存储在 *idx 中。
  • 返回值 :转换后的结果。
  • 异常抛出 :若 strtof strtod strtold 报告无法进行转换,则抛出 invalid_argument 异常;若转换值超出返回类型的可表示范围,或 strtof strtod strtold errno 设置为 ERANGE ,则抛出 out_of_range 异常。
2.3 整数/浮点数转字符串
string to_string(int val);
string to_string(unsigned val);
string to_string(long val);
string to_string(unsigned long val);
string to_string(long long val);
string to_string(unsigned long long val);
string to_string(float val);
string to_string(double val);
string to_string(long double val);

每个函数返回一个 string 对象,该对象包含其参数值的字符表示,其生成方式等同于调用 sprintf(buf, fmt, val) ,格式说明符分别为 "%d" "%u" "%ld" "%lu" "%lld" "%llu" "%f" "%f" "%Lf" ,其中 buf 是一个足够大的内部字符缓冲区。

3. 宽字符串数值转换函数

宽字符串也有类似的数值转换函数,例如:

int stoi(const wstring& str, size_t* idx = nullptr, int base = 10);
long stol(const wstring& str, size_t* idx = nullptr, int base = 10);
unsigned long stoul(const wstring& str, size_t* idx = nullptr, int base = 10);
long long stoll(const wstring& str, size_t* idx = nullptr, int base = 10);
unsigned long long stoull(const wstring& str, size_t* idx = nullptr, int base = 10);

其效果、返回值和异常抛出情况与普通字符串的转换函数类似,只是调用的是宽字符版本的函数,如 wcstol wcstoul 等。

4. 哈希支持

对于多种字符串类型,提供了哈希支持:

template<> struct hash<string>;
template<> struct hash<u8string>;
template<> struct hash<u16string>;
template<> struct hash<u32string>;
template<> struct hash<wstring>;
template<> struct hash<pmr::string>;
template<> struct hash<pmr::u8string>;
template<> struct hash<pmr::u16string>;
template<> struct hash<pmr::u32string>;
template<> struct hash<pmr::wstring>;

S 是这些字符串类型之一, SV 是对应的字符串视图类型, s S 类型的对象,则有 hash<S>()(s) == hash<SV>()(SV(s))

5. 字符串字面量后缀

为字符串字面量提供了后缀 s

string operator""s(const char* str, size_t len);
u8string operator""s(const char8_t* str, size_t len);
u16string operator""s(const char16_t* str, size_t len);
u32string operator""s(const char32_t* str, size_t len);
wstring operator""s(const wchar_t* str, size_t len);

这些运算符返回相应类型的字符串对象,包含指定的字符序列。

6. 字符串视图类
6.1 概述

basic_string_view 类模板描述了一个可以引用常量连续字符序列的对象,序列的第一个元素位于位置零。该库提供了从 const charT* std::basic_string<charT, ...> std::basic_string_view<charT, ...> 的隐式转换,方便用户代码在需要字符序列的地方接受 std::basic_string_view<charT> 作为非模板参数。

6.2 头文件概述

<string_view> 头文件包含以下内容:

namespace std {
    // 类模板 basic_string_view
    template<class charT, class traits = char_traits<charT>>
    class basic_string_view;
    // 非成员比较函数
    template<class charT, class traits>
    constexpr bool operator==(basic_string_view<charT, traits> x,
                              basic_string_view<charT, traits> y) noexcept;
    // 其他比较运算符...
    // 插入器和提取器
    template<class charT, class traits>
    basic_ostream<charT, traits>&
    operator<<(basic_ostream<charT, traits>& os,
               basic_string_view<charT, traits> str);
    // 类型别名
    using string_view = basic_string_view<char>;
    using u8string_view = basic_string_view<char8_t>;
    using u16string_view = basic_string_view<char16_t>;
    using u32string_view = basic_string_view<char32_t>;
    using wstring_view = basic_string_view<wchar_t>;
    // 哈希支持
    template<class T> struct hash;
    template<> struct hash<string_view>;
    // 其他哈希特化...
    // 字符串视图字面量后缀
    inline namespace literals {
        inline namespace string_view_literals {
            constexpr string_view operator""sv(const char* str, size_t len) noexcept;
            // 其他后缀运算符...
        }
    }
}
6.3 类模板 basic_string_view
template<class charT, class traits = char_traits<charT>>
class basic_string_view {
public:
    // 类型定义
    using traits_type = traits;
    using value_type = charT;
    // 其他类型定义...
    static constexpr size_type npos = size_type(-1);
    // 构造和赋值
    constexpr basic_string_view() noexcept;
    constexpr basic_string_view(const basic_string_view&) noexcept = default;
    constexpr basic_string_view(const charT* str);
    constexpr basic_string_view(const charT* str, size_type len);
    // 迭代器支持
    constexpr const_iterator begin() const noexcept;
    // 其他迭代器函数...
    // 容量
    constexpr size_type size() const noexcept;
    constexpr size_type length() const noexcept;
    // 元素访问
    constexpr const_reference operator[](size_type pos) const;
    constexpr const_reference at(size_type pos) const;
    // 修改器
    constexpr void remove_prefix(size_type n);
    constexpr void remove_suffix(size_type n);
    constexpr void swap(basic_string_view& s) noexcept;
    // 字符串操作
    constexpr size_type copy(charT* s, size_type n, size_type pos = 0) const;
    constexpr basic_string_view substr(size_type pos = 0, size_type n = npos) const;
    // 搜索
    constexpr size_type find(basic_string_view s, size_type pos = 0) const noexcept;
    // 其他搜索函数...
private:
    const_pointer data_;
    size_type size_;
};

以下是 basic_string_view 构造函数的流程图:

graph TD;
    A[开始] --> B{选择构造函数};
    B -->|basic_string_view()| C[构造空的 basic_string_view];
    C --> D[size_ = 0, data_ = nullptr];
    B -->|basic_string_view(const charT* str)| E{[str, str + traits::length(str)) 是否有效};
    E -->|是| F[初始化 data_ 为 str, size_ 为 traits::length(str)];
    E -->|否| G[错误,范围无效];
    B -->|basic_string_view(const charT* str, size_type len)| H{[str, str + len) 是否有效};
    H -->|是| I[初始化 data_ 为 str, size_ 为 len];
    H -->|否| J[错误,范围无效];
    D --> K[结束];
    F --> K;
    I --> K;
    G --> K;
    J --> K;

以下是 basic_string_view 部分操作的总结表格:
| 操作类型 | 函数 | 功能 | 复杂度 |
| ---- | ---- | ---- | ---- |
| 构造 | basic_string_view() | 构造空的视图 | O(1) |
| 构造 | basic_string_view(const charT* str) | 从字符串构造视图 | O(traits::length(str)) |
| 构造 | basic_string_view(const charT* str, size_type len) | 从指定长度的字符串构造视图 | O(1) |
| 容量 | size() | 返回视图的大小 | O(1) |
| 元素访问 | operator[](size_type pos) | 访问指定位置的元素 | O(1) |
| 修改器 | remove_prefix(size_type n) | 移除前缀 | O(1) |
| 修改器 | remove_suffix(size_type n) | 移除后缀 | O(1) |
| 搜索 | find(basic_string_view s, size_type pos = 0) | 查找子视图 | 未指定 |

C++ 字符串处理与视图类详解

7. basic_string_view 详细解析
7.1 类型要求

在每个 basic_string_view<charT, traits> 特化中, traits 类型必须满足字符特征要求。需要注意的是,如果 traits::char_type charT 不是同一类型,程序将是格式错误的。同时, iterator 类型要满足常量表达式迭代器要求,并且 basic_string_view 成员函数的复杂度通常为 O(1),除非另有说明。

7.2 构造与赋值

basic_string_view 提供了多种构造函数:
- constexpr basic_string_view() noexcept; :此构造函数用于构造一个空的 basic_string_view ,构造后能确保 size_ == 0 data_ == nullptr
- constexpr basic_string_view(const charT* str); :该构造函数期望 [str, str + traits::length(str)) 是一个有效范围,它会用 str 初始化 data_ ,用 traits::length(str) 初始化 size_ ,其复杂度为 O(traits::length(str))。
- constexpr basic_string_view(const charT* str, size_type len); :这个构造函数要求 [str, str + len) 是有效范围,它会用 str 初始化 data_ ,用 len 初始化 size_

以下是构造函数的使用示例表格:
| 构造函数 | 使用示例 | 说明 |
| ---- | ---- | ---- |
| basic_string_view() | basic_string_view<char> sv1; | 构造空视图 |
| basic_string_view(const charT* str) | const char* s = "hello"; basic_string_view<char> sv2(s); | 从字符串构造视图 |
| basic_string_view(const charT* str, size_type len) | basic_string_view<char> sv3(s, 3); | 从指定长度字符串构造视图 |

7.3 迭代器支持

basic_string_view 提供了丰富的迭代器支持:

constexpr const_iterator begin() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator end() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr const_reverse_iterator rbegin() const noexcept;
constexpr const_reverse_iterator rend() const noexcept;
constexpr const_reverse_iterator crbegin() const noexcept;
constexpr const_reverse_iterator crend() const noexcept;

const_iterator 是一个满足常量 Cpp17 随机访问迭代器要求并模拟连续迭代器的类型,其 value_type 为模板参数 charT 。对于 basic_string_view str ,任何使 [str.data(), str.data() + str.size()) 范围内指针无效的操作,都会使 str 成员函数返回的指针、迭代器和引用无效。

以下是迭代器使用的流程图:

graph TD;
    A[开始] --> B[创建 basic_string_view 对象];
    B --> C[获取 begin() 迭代器];
    C --> D{是否到达 end()};
    D -->|否| E[访问当前元素];
    E --> F[迭代器递增];
    F --> D;
    D -->|是| G[结束];
7.4 容量操作

basic_string_view 提供了几个用于查询容量的函数:

constexpr size_type size() const noexcept;
constexpr size_type length() const noexcept;
constexpr size_type max_size() const noexcept;
[[nodiscard]] constexpr bool empty() const noexcept;

size() length() 都返回 size_ max_size() 返回 basic_string_view 能引用的最大字符对象数, empty() 用于判断视图是否为空。

以下是容量操作的总结表格:
| 函数 | 功能 | 返回值 | 复杂度 |
| ---- | ---- | ---- | ---- |
| size() | 返回视图大小 | size_ | O(1) |
| length() | 返回视图长度 | size_ | O(1) |
| max_size() | 返回最大可引用字符数 | 最大字符数 | O(1) |
| empty() | 判断视图是否为空 | true false | O(1) |

7.5 元素访问

basic_string_view 提供了多种元素访问方式:

constexpr const_reference operator[](size_type pos) const;
constexpr const_reference at(size_type pos) const;
constexpr const_reference front() const;
constexpr const_reference back() const;
constexpr const_pointer data() const noexcept;

operator[](size_type pos) 要求 pos < size() ,返回 data_[pos] ,且不会抛出异常; at(size_type pos) pos >= size() 会抛出 out_of_range 异常; front() 要求视图不为空,返回 data_[0] back() 也要求视图不为空,返回 data_[size() - 1] data() 返回 data_ ,需注意该指针指向的缓冲区可能未以空字符结尾。

以下是元素访问的使用示例列表:
1. 使用 operator[]

basic_string_view<char> sv("hello");
char c = sv[1]; // c 为 'e'
  1. 使用 at
try {
    char c = sv.at(2); // c 为 'l'
    char d = sv.at(5); // 抛出 out_of_range 异常
} catch (const std::out_of_range& e) {
    std::cerr << e.what() << std::endl;
}
  1. 使用 front back
char f = sv.front(); // f 为 'h'
char b = sv.back(); // b 为 'o'
  1. 使用 data
const char* ptr = sv.data();
7.6 修改器

basic_string_view 提供了两个修改器函数:

constexpr void remove_prefix(size_type n);
constexpr void remove_suffix(size_type n);

remove_prefix(size_type n) 要求 n <= size() ,其效果等同于 data_ += n; size_ -= n; remove_suffix(size_type n) 同样要求 n <= size() ,效果等同于 size_ -= n;

以下是修改器使用的流程图:

graph TD;
    A[开始] --> B[创建 basic_string_view 对象];
    B --> C{选择修改器};
    C -->|remove_prefix(size_type n)| D{ n <= size()? };
    D -->|是| E[data_ += n, size_ -= n];
    D -->|否| F[错误,n 超出范围];
    C -->|remove_suffix(size_type n)| G{ n <= size()? };
    G -->|是| H[size_ -= n];
    G -->|否| I[错误,n 超出范围];
    E --> J[结束];
    F --> J;
    H --> J;
    I --> J;

通过对 basic_string_view 的详细解析,我们可以看到它在处理字符串时提供了高效、灵活且安全的方式,能帮助开发者更好地处理和操作字符串数据。同时,C++ 中丰富的字符串处理函数和哈希支持等特性,也为字符串的各种操作提供了全面的解决方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值