c++23 使用 `std::views::split` 和 `std::views::join` 实现字符串分割和连接

发布时间:2025-05-14      访问量:50
`std::views::split` 和 `std::views::join` 是 C++20 引入的范围适配器(Range Adaptors),用于字符串分割和连接操作。它们提供了惰性计算(lazy evaluation)的特性,避免了临时容器的创建,提高了效率和代码简洁性。


**一、std::views::split**
**功能**
将一个范围(如字符串)按指定分隔符分割为多个子范围。

**基本用法**
cpp #include <iostream> #include <ranges> #include <string> int main() { std::string text = "hello,world,example"; auto words = text | std::views::split(','); for (auto word : words) { // word 是一个字符子范围,转换为 string 输出 std::cout << std::string(word.begin(), word.end()) << '\n'; } // 输出: // hello // world // example }

**技术细节**
1. **分隔符类型**:
- 单个字符:如 `','`
- 字符范围:如 `std::string("-,")`
```cpp
std::string text = "a-b,c";
auto parts = text | std::views::split(std::string_view("-,"));
// 分割为 {"a", "b", "c"}
```

2. **空字符串处理**:
- 连续分隔符会产生空字符串。
```cpp
std::string text = "a,,b";
auto parts = text | std::views::split(',');
// 分割为 {"a", "", "b"}
```

3. **惰性计算**:
- 不立即生成所有子字符串,而是在迭代时按需计算。


**二、std::views::join**
**功能**
将多个范围连接为一个单一范围。

**基本用法**
cpp #include <iostream> #include <ranges> #include <vector> #include <string> int main() { std::vector<std::string> words = {"hello", "world", "!"}; auto joined = words | std::views::join; // 输出连接后的字符范围 for (char c : joined) { std::cout << c; } // 输出: helloworld! }

**结合分隔符使用**
若需在元素间添加分隔符,可配合 `std::views::transform` 和 `std::views::join`:
cpp std::vector<std::string> words = {"hello", "world", "!"}; auto with_space = words | std::views::transform([](const auto& s) { return std::views::concat(s, std::views::single(' ')); }); auto joined = with_space | std::views::join; // 输出: hello world !

**技术细节**
1. **输入要求**:
- 必须是范围的范围(如 `vector<string>`)。
- 若直接对字符串使用 `join` 会报错,需先包装为范围:
```cpp
std::string s = "abc";
auto wrapped = std::views::single(s);
auto joined = wrapped | std::views::join; // 正确
```

2. **惰性计算**:
- 与 `split` 类似,仅在迭代时生成结果。


**三、组合使用**
分割后再连接:
cpp std::string text = "a,b,c"; auto split_view = text | std::views::split(','); auto joined_view = split_view | std::views::join; // 将 joined_view 转换为字符串 std::string result(joined_view.begin(), joined_view.end()); // result = "abc"


**四、注意事项**
1. **临时对象生命周期**:
```cpp
// 错误:临时字符串在 split 操作前已销毁
auto parts = std::string("a,b,c") | std::views::split(',');

// 正确:延长临时对象生命周期
auto parts = std::views::owning_view(std::string("a,b,c")) | std::views::split(',');
```

2. **空范围处理**:
- 空输入会生成空输出,不会导致异常。

3. **性能优势**:
- 避免了中间容器的内存分配,适合处理大型数据。


**五、与传统方法对比**
| 操作 | 传统方法 | 范围适配器方法 |
|---------------|------------------------------|--------------------------------|
| 字符串分割 | `std::stringstream` + getline| `std::views::split` |
| 字符串连接 | `std::string::append` | `std::views::join` |
| 临时容器 | 需要(如 `vector<string>`) | 不需要(惰性计算) |
| 代码复杂度 | 较高 | 较低(链式调用) |


**总结**
- **`std::views::split`**:用于字符串分割,支持惰性计算,返回子范围视图。
- **`std::views::join`**:用于范围连接,同样支持惰性计算,避免临时容器。
- **适用场景**:处理大型文本、数据流或需要高效内存使用的场景。
堆内存
多线程
strdup
初始化器
冒泡排序
增删改查
BufferedReader
输入输出
面向对象
生命周期
闭包的概念
原型链
Flask
mysql-connector-python
单例模式
浅拷贝
隔离级别
索引
InnoDB
左连接
聚合函数
PuTTY
TRUNCATE
str_starts_with_many
DateTime
array_combine
闭包的概念