限制std::views::split生成的子区间数量

编程语言 2026-07-09
#include <iomanip>
#include <iostream>
#include <ranges>
#include <string_view>

int main()
{
    using std::operator""sv;
    constexpr auto words{"Hello C++ 20!"sv};

    for (const auto word : std::views::split(words, ' '))
        std::cout << std::quoted(std::string_view(word)) << ' ';
    std::cout << '\n';
}

此链接 的输出是 "Hello" "C++" "20!"

如何使用 n 限制分割数量并获得输出:"Hello" "C++ 20!"(使用 n = 1,从开头开始单次分割,第一子区间是 Hello,第二子区间是第一個空格之后的所有字符。)

这可以在C++26中像下面这样实现,但我受限于C++20。

auto split = std::views::split(words, ' ');
auto first = split | std::views::take(n);
auto tail = split | std::views::drop(n);
auto ret = std::views::concat(first, tail);

解决方案

你可以先使用 views::take(n) 获取特定分割数量的子串,然后通过访问 views::take(n) 结束迭代器的底层 string_view 迭代器(具备 .base() 成员)来获取剩余的字符串:

auto split = std::views::split(words, ' ');
auto split_n = split | std::views::take(n);
// specific split amount split
for (const auto word : split_n)
  std::cout << std::quoted(std::string_view(word.begin(), word.end())) << ' ';
// remaining
const auto rest = std::string_view(
  std::ranges::next(split_n.begin(), split_n.end()).base().base(),
  words.end());
if (!rest.empty())
  std::cout << std::quoted(rest);

示例

说明:

words | views::split(' ') 产生由 string_view::iterator-对组成的三个子区间:"Hello""C++""20!"。如果随后应用 views::take(1),我们将得到一个 take_view,它将只包含第一子区间,即 "Hello"

在这种情况下,这个 take_view 的末端实际上指向第二个子区间的起点,即 "C++"。通过调用 ranges::next,我们可以得到一个指向 take_view 末端的 take_view::iterator

第一个 .base() 从这个 take_view::iterator 中提取底层的 split_view::iterator,第二个 .base()split_view::iterator 中提取底层的 string_view::iterator

因此,我们最终得到一个指向 "C++"string_view::iterator,由这个迭代器与 words.end() 组成的新 string_view"C++ 20!"

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章