使用range-v3读取逗号分隔的数字列表

时间:2019-12-02 22:26:03

标签: c++ c++20 range-v3

我想使用Ranges(我使用range-v3实现)来读取输入流,该输入流是逗号分隔的数字列表。在没有范围的情况下这样做是微不足道的,但是... 我认为这是解决问题的简单方法:

auto input = std::istringstream("42,314,11,0,14,-5,37");
auto ints = ranges::istream_view<int>(input) | ranges::view::split(",");
for (int i : ints)
{
    std::cout << i << std::endl;
}

但这无法编译。我已经尝试了多种变体,但似乎无济于事,我猜这在几种方面都是错误的。有人可以告诉我我做错了什么,然后解释该怎么做吗?

谢谢!

2 个答案:

答案 0 :(得分:4)

什么

ranges::istream_view<int>(input)

确实会产生一个与该协程大致相当的范围(即使您不了解C ++ 20协程,也希望此示例足够简单以至于可以理解这一点):

generator<int> istream_view_ints(istream& input) {
    int i;
    while (input >> i) {  // while we can still stream int's out
       co_yield i;        // ... yield the next int
    }
}

这里有两个要点:

  1. 这是int的范围,因此不能在字符串上split
  2. 这使用常规流>>,该流不允许您提供自己的定界符-它仅在空白处停止。

istream_view<int>(input)总共为您提供了int的范围,这些范围在您的输入中仅包含一个int:仅42。下一个输入将尝试读入,并失败。


为了获得定界输入,可以使用getlines。这将为您提供string范围以及您提供的定界符。它在内部使用std::getline。实际上,这就是协程:

generator<string> getlines(istream& input, char delim = '\n') {
    string s;
    while (std::getline(input, s, delim)) {
        co_yield s;
    }
}

然后您需要将这些string转换为int。这样的事情应该可以解决问题:

auto ints = ranges::getlines(input, ',')
          | ranges::view::transform([](std::string const& s){ return std::stoi(s); });

答案 1 :(得分:1)

std::string input = "42,314,11,0,14,-5,37";
auto split_view = ranges::view::split(input, ",");

会产生一系列范围:

{{'4', '2'}, {'3', '1', '4'}, {'1', '1'}, {'0'}, {'1', '4'}, {'-', '5'}, {'3', '7'}}

所以您可以这样做:

std::string input = "42,314,11,0,14,-5,37";
auto split_view = ranges::view::split(input, ",");
for (auto chars : split_view) {
    for (auto c : chars) {
        std::cout << c;
    }
    std::cout << std::endl;
}