使用range-v3读取包含逗号分隔数据的行

时间:2019-12-28 22:23:30

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

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

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

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

因此,我的想法很简单,就是使用range :: getlines(或range :: istream_view)从istream读取数据行,将每行传送到以逗号分隔的split view适配器,以获取单词(例如范围的范围,然后我加入),最后对每个单词进行变换/解码,然后将其放入向量中。恕我直言,它应该超级简单,就像:

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问题的链接:Using range-v3 to read comma separated list of numbers

1 个答案:

答案 0 :(得分:3)

  

拆分视图适配器似乎根本不拆分行,因为整行都作为要转换的参数传递-为什么呢?

因为这正是您不小心要的。

split是一个适配器,其取值范围为T,产生的取值范围为T,由单个T或一个分隔符分隔本身的范围为T

写时:

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

lines是一个字符串范围(不是单个字符串),您要用单个逗号分隔该字符串范围。如果您有一系列像["A", ",", "B", "C", "D", ",", "E"]这样的字符串(即7个字符串,其中第2个和第6个是逗号),那么您将得到[["A"], ["B", "C", "D"], ["E"]]

但这不是您想要的。

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

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

这将使您的RangeOf<string>变成RangeOf<RangeOf<RangeOf<char>>>(这只会增加一层range-ness ...因为string是{{1} }。但是我们失去了RangeOf<char>-ness)。

然后您可以将string一起使用:

join

现在我们回到lines | views::transform([](auto const& s) { return s | views::split(','); }) | views::join; 。如果我们真正想要的是RangeOf<RangeOf<char>>,则需要将每个元素重新收集为一个:

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中。