Using range-v3 to read comma separated list of numbers

半腔热情 提交于 2020-01-24 09:28:46

问题


I'd like to use Ranges (I use range-v3 implementation) to read a input stream that is a comma separated list of numbers. That is trivial to do without ranges but... This is what I thought was the straight-forward way to solve it:

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;
}

But this fails to compile. I've tried a number of variations of this but nothing seem to work, I guess this is wrong in several ways. Can someone please enlighten me what I am doing wrong and explain how this should be done instead?

Thanks in advance!


回答1:


What

ranges::istream_view<int>(input)

does is produce a range that is the rough equivalent of this coroutine (even if you don't understand C++20 coroutines, hopefully this example is simple enough that it gets the point across):

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
    }
}

Two important points here:

  1. This is range of ints, so you cannot split it on a string.
  2. This uses the normal stream >>, which does not allow you to provide your own delimiter - it only stops at whitespace.

Altogether, istream_view<int>(input) gives you a range of ints that, on your input, consists of a single int: just 42. The next input would try to read in the , and fail.


In order to get a delimited input, you can use getlines. That will give you a range of string with the delimiter you provide. It uses std::getline internally. Effectively, it's this coroutine:

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

And then you need to convert those strings to ints. Something like this should do the trick:

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



回答2:


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

would produce a range of ranges:

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

so you might do:

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;
}


来源:https://stackoverflow.com/questions/59147560/using-range-v3-to-read-comma-separated-list-of-numbers

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!