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_splitauto 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_typefor (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 } { ! }