首页 > 解决方案 > 使用 range-v3 读取逗号分隔数据的行

问题描述

再次是的,因为我最近问了一个非常相似的问题(如何读取逗号分隔的整数列表),但是这次我被困在读取由逗号分隔的数据组成的字符串行上。将我之前处理整数的代码转换为处理数据块字符串肯定很简单,对吧?

好的,所以我从一个文件或标准输入中读取数据,该文件或标准输入有很多行,其中包含用逗号分隔的单词,例如:

hello,this,is,firstrow,sdf763  
this,is,2nd,row  
and,so,on314  

所以,我的想法是简单地使用ranges::getlines(或ranges::istream_view)从istream中读取数据行,将每一行通过逗号传递到拆分视图适配器以获取单词(作为一个范围,然后我加入)并最终转换/解码每个单词,然后将其放入向量中。恕我直言,它应该非常简单,就像:

std::string decode(const std::string& word);

int main()
{
    using namespace ranges;
    auto lines = getlines(std::cin);           // ["hello,this,is,firstrow,sdf763" "this,is,2nd,row" "and,so,on314" ...]
    auto words = lines | view::split(",");     // [["hello" "this" "is" "firstrow" "sdf763"] ["this" "is" "2nd" "row"] [...]]
    auto words_flattened = words | view::join; // ["hello" "this" "is" "firstrow" "sdf763" "this" "is" "2nd" "row" ...]
    auto decoded_words = words_flattened | view::transform([](const auto& word){
        return decode(word);
    }) | to_vector;

    for (auto word : decoded_words) {
        std::cout << word << "\n";
    }
    std::cout << std::endl;
}

但是不,这不起作用,我不知道为什么!拆分视图适配器似乎根本没有拆分行,因为整行作为参数传递给 transform - 为什么会这样?我显然仍在学习范围,并且似乎仍然错过了一些基本概念......如果有人能解释发生了什么,我当然会很感激,在此先感谢!

我之前的 SO 问题的链接:使用 range-v3 读取逗号分隔的数字列表

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

解决方案


拆分视图适配器似乎根本没有拆分行,因为整行作为参数传递给 transform - 为什么会这样?

因为这正是你不小心要求的。

split是一个适配器,它接受一个范围T并产生一个范围的范围T,在一个分隔符上进行拆分,该分隔符要么是单个的,T要么本身就是一个Ts 的范围。

当你写:

lines | views::split(",");

lines是一个字符串范围(不是单个字符串),并且您要求将该字符串范围划分为单个逗号的字符串。如果你有一系列字符串["A", ",", "B", "C", "D", ",", "E"](即 7 个​​字符串,其中第 2 个和第 6 个是逗号),你会得到 back [["A"], ["B", "C", "D"], ["E"]]

但这不是你想要的。

你想要的是用逗号分割每个字符串。那是:

lines | views::transform([](auto const& s) { return s | views::split(','); })

这需要你RangeOf<string>并将其变成 a RangeOf<RangeOf<RangeOf<char>>>(这只增加了一层range-ness... 因为string是 a RangeOf<char>。但我们失去了string-ness )。

然后,您可以将join它们放在一起:

lines | views::transform([](auto const& s) { return s | views::split(','); })
      | views::join;

现在我们回到RangeOf<RangeOf<char>>. 如果我们真正想要的是 a RangeOf<string>,我们需要将每个元素收集回一个:

lines | views::transform([](auto const& s) { return s | views::split(','); })
      | views::join
      | views::transform([](auto const& rc) { return rc | to<std::string>; });

或者,您可以将第二个变换移动到第一个变换中,以便在您string之前收集到 s 中join


推荐阅读