能否使用std::ranges::split_view搭配可比较但非同源类型的分隔符?
关于用std::views::split实现按任意空白符拆分char范围的问题
结论是:没法直接用std::views::split实现这种需求,但可以通过组合标准库的其他视图来达到同样效果,或者换用更适配的工具。
原因
std::views::split的核心逻辑是匹配固定的分隔符序列——它需要你提供一个明确的范围(比如单个字符、字符串)作为分隔符,然后在原范围里找完全匹配这个序列的位置来拆分。而“按任意空白符拆分”是基于单个字符是否满足空白条件的谓词逻辑,和split的设计初衷不匹配,自然没法直接用自定义的Whitespace结构体作为分隔符。
替代实现方案
方案1:用group_by + filter直接拆分(推荐)
这种方式直接针对“连续空白视为单个分隔”的需求,一步到位:
#include <ranges> #include <string> #include <cctype> #include <iostream> int main() { std::string s = "hello world\tfoo\nbar"; // 先按"是否同为空白/非空白"分组,再过滤掉空白组 auto split_result = s | std::views::group_by([](char a, char b) { return std::isspace(static_cast<unsigned char>(a)) == std::isspace(static_cast<unsigned char>(b)); }) | std::views::filter([](auto&& group) { return !std::isspace(static_cast<unsigned char>(*group.begin())); }); // 遍历输出拆分结果 for (auto&& part : split_result) { std::cout << std::string(part) << "\n"; } }
这个方案不需要预处理,效率也更高,完全符合“按任意空白符拆分,连续空白算一个”的需求。
方案2:预处理后再用split(凑合用)
如果非要依赖std::views::split,可以先把所有空白字符统一成同一个(比如空格),再压缩连续的空格为单个,最后用split(' ')拆分,还要过滤掉空的子范围:
#include <ranges> #include <string> #include <cctype> #include <iostream> int main() { std::string s = "hello world\tfoo\nbar"; // 第一步:把所有空白转成空格 auto normalized = s | std::views::transform([](char c) { return std::isspace(static_cast<unsigned char>(c)) ? ' ' : c; }) // 第二步:压缩连续空格为单个 | std::views::group_by([](char a, char b) { return a == b; }) | std::views::transform([](auto&& group) { return *group.begin(); }); // 第三步:用空格拆分,再过滤空范围 auto split_result = normalized | std::views::split(' ') | std::views::filter([](auto&& part) { return !part.empty(); }); for (auto&& part : split_result) { std::cout << std::string(part) << "\n"; } }
这种方式步骤冗余,不如方案1高效,只是满足了“用split”的形式需求。
方案3:C++23的views::tokenize(更适配)
如果你的编译器支持C++23,可以用std::views::tokenize,它专门支持基于谓词的拆分:
#include <ranges> #include <string> #include <cctype> #include <iostream> int main() { std::string s = "hello world\tfoo\nbar"; // 提取所有非空白的连续字符序列 auto split_result = s | std::views::tokenize([](char c) { return !std::isspace(static_cast<unsigned char>(c)); }); for (auto&& part : split_result) { std::cout << std::string(part) << "\n"; } }
这个工具的设计就是用来处理“按规则提取 token”的场景,完美匹配你的需求。
内容的提问来源于stack exchange,提问作者Fureeish
相关产品推荐
相关产品推荐

