使用 range-v3 读取逗号分隔的数字列表
Using range-v3 to read comma separated list of numbers
我想使用 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;
}
但是编译失败。我已经尝试了很多变体,但似乎没有任何效果,我想这在几个方面都是错误的。有人可以告诉我我做错了什么并解释应该怎么做吗?
提前致谢!
什么
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
}
}
这里有两个要点:
- 这是
int
的范围,所以你不能 split
它在一个字符串上。
- 这使用普通流
>>
,它不允许您提供自己的定界符 - 它只在空格处停止。
总而言之,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); });
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;
}
我想使用 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;
}
但是编译失败。我已经尝试了很多变体,但似乎没有任何效果,我想这在几个方面都是错误的。有人可以告诉我我做错了什么并解释应该怎么做吗?
提前致谢!
什么
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
}
}
这里有两个要点:
- 这是
int
的范围,所以你不能split
它在一个字符串上。 - 这使用普通流
>>
,它不允许您提供自己的定界符 - 它只在空格处停止。
总而言之,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); });
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;
}