std::ranges::views::split, lazy_split, std::ranges::split_view, lazy_split_view
std::ranges::views::split, std::ranges::split_view
C++20 中引入的用于分割范围(range)的组件,允许将输入范围按特定分隔符或条件分割成多个子范围。以下是详细说明和示例:
基本概念
1. 功能
- 分割范围:将输入范围(如字符串、容器)按指定的分隔符(可以是单个元素、子范围或谓词)分割成多个子范围。
- 惰性求值:
split_view
是惰性适配器,只有在遍历时才会执行分割操作,不会预先分配内存。 - 返回类型:返回一个
split_view
对象,其元素是subrange
类型的子范围。
语法与参数
1. 语法
auto split_view = input_range | std::ranges::views::split(pattern);
input_range
:输入范围(如std::string
、std::vector
)。pattern
:分隔符,可以是以下类型:- 单个元素(如
char
、int
)。 - 子范围(如
std::string_view
、std::vector
)。 - 谓词(需满足
std::indirect_unary_predicate
)。
- 单个元素(如
示例
示例 1:使用字符分割字符串
#include <iostream>
#include <ranges>
#include <string>
#include <vector>
using namespace std;
int main() {
string str = "apple,banana,cherry";
// 使用 views::split 替代 views::lazy_split
auto split_view = str | views::split(',');
for (auto const& word : split_view) {
// 正确转换子范围到字符串的两种方式:
// 方式 1:使用 ranges::to(C++23 特性)
// cout << ranges::to<string>(word) << endl;
// 方式 2:传统构造方式(兼容 C++20)
cout << string{word.begin(), word.end()} << endl;
}
}
output:
apple
banana
cherry
示例 2:使用子范围分割字符串
#include <iostream>
#include <ranges>
#include <string>
int main() {
std::string str = "apple::banana::cherry";
std::string_view delimiter = "::";
auto split_view = str | std::ranges::views::split(delimiter);
for (const auto& subrange : split_view) {
std::string word{subrange.begin(), subrange.end()};
std::cout << word << "\n";
}
}
示例 3:处理空子范围
当输入以分隔符开头或结尾时,会产生空子范围:
#include <iostream>
#include <ranges>
#include <string>
int main() {
std::string str = ",apple,,banana,";
auto split_view = str | std::ranges::views::split(',');
for (const auto& subrange : split_view) {
std::string word{subrange.begin(), subrange.end()};
std::cout << (word.empty() ? "[empty]" : word) << "\n";
}
}
outpu:
[empty]
apple
[empty]
banana
[empty]
示例 4:分割容器
#include <iostream>
#include <ranges>
#include <vector>
int main() {
std::vector<int> data = {1, 0, 2, 0, 3, 0, 4};
auto split_view = data | std::ranges::views::split(0);
for (const auto& subrange : split_view) {
std::vector<int> segment{subrange.begin(), subrange.end()};
for (int num : segment) std::cout << num << " ";
std::cout << "\n";
}
}
output:
1
2
3
4
注意事项
-
子范围生命周期:
split_view
的子范围是输入范围的视图,确保输入范围在子范围使用时仍然有效。
-
性能优化:
- 避免多次遍历同一子范围。若需多次使用,可将其转换为容器(如
std::string
、std::vector
)。
- 避免多次遍历同一子范围。若需多次使用,可将其转换为容器(如
-
C++23 的
ranges::to
:- 若使用 C++23,可用
ranges::to
直接转换子范围:
- 若使用 C++23,可用
#include <ranges>
std::cout << std::ranges::to<std::string>(subrange) << "\n";
总结
- 核心用途:高效分割范围,无需内存拷贝。
- 适用场景:处理字符串分割、日志解析、数据流分析等。
- 关键接口:
views::split
和split_view
,结合subrange
迭代器操作。
std::ranges::views::lazy_split, std::ranges::lazy_split_view
C++20 引入的惰性范围适配器,用于将输入范围按指定分隔符分割成多个子范围。它不会立即执行分割,而是在遍历时动态生成子范围,适用于处理大型数据或需要延迟计算的场景。
基本用法
-
头文件:
<ranges>
-
语法:
input_range | views::lazy_split(pattern)
-
参数:
-
input_range
: 要分割的范围(如字符串、容器等)。 -
pattern
: 分隔符,可以是单个元素或一个子范围。
-
示例代码
示例 1:
#include <algorithm>
#include <iostream>
#include <ranges>
#include <string_view>
auto print = [](auto const& view)
{
// `view` is of std::views::lazy_split_view::__outer_iterator::value_type
for (std::cout << "{ "; const auto element : view)
std::cout << element << ' ';
std::cout << "} ";
};
int main()
{
constexpr static auto source = {0, 1, 0, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9};
constexpr int delimiter{0};
constexpr std::ranges::lazy_split_view outer_view{source, delimiter};
std::cout << "splits[" << std::ranges::distance(outer_view) << "]: ";
for (auto const& inner_view: outer_view)
{
print(inner_view);
}
constexpr std::string_view hello{"Hello C++ 20 !"};
std::cout << "\n" "substrings: ";
//std::ranges::for_each(hello | std::views::lazy_split(' '), print);
const auto substr = hello | std::views::lazy_split(' ');
for (auto const& str: substr)
{
print(str);
}
constexpr std::string_view text{"Hello-+-C++-+-20-+-!"};
constexpr std::string_view delim{"-+-"};
std::cout << "\n" "substrings: ";
std::ranges::for_each(text | std::views::lazy_split(delim), print);
}
Output:
splits[5]: { } { 1 } { 2 3 } { 4 5 6 } { 7 8 9 } substrings: { H e l l o } { C + + } { 2 0 } { ! } substrings: { H e l l o } { C + + } { 2 0 } { ! }