gpt4 book ai didi

c++ - 从文件中逐字读取

转载 作者:行者123 更新时间:2023-12-02 10:38:20 25 4
gpt4 key购买 nike

我有一门课是Food,其.h是:

class Food{

private:

string name;

int protein;

int calories;

int fats;

string type;

public:

....

friend istream & operator >> (istream &i, Food & other);

};

因此,使用运算符>>,我想从具有以下格式的文件中读取一种食物的属性:
Ketchup;98;24;2;Processed

我试着做:
istream & operator >> (istream &i, Food & other){
string nom, t;

int c, p, h, g, f;

char aux; //Aux stores ';'

i >> nom >> aux >> c >> aux >> p >> aux >> f;

getline(i,t); //I read the type and change the line that I'm reading

Food ing(nom.c_str(),c,p,f,t.c_str()); //Constructor

other = ing; //Overload of operator =

return i;
}

但是我没有成功,请帮忙吗?

最佳答案

好像您要读取csv数据。这是一项标准任务,我将为您提供详细说明。最后,所有阅读将以单线完成。

我建议使用“现代” C++方法。

仍然所有谈论csv的人都链接到How can I read and parse CSV files in C++?,问题是从2009年开始的,现在已经超过10年了。大多数答案也很老而且很复杂。因此,也许是时候改变了。

在现代C++中,您具有遍历范围的算法。您通常会看到类似“someAlgoritm(container.begin(),container.end(),someLambda)”的内容。这个想法是我们迭代一些相似的元素。

在您的情况下,我们遍历输入字符串中的标记,并创建子字符串。这称为标记化。

正是出于这个目的,我们有了std::sregex_token_iterator。并且因为我们已经为此目的定义了一些东西,所以我们应该使用它。

这个东西是一个迭代器。用于遍历字符串,因此使用sregex。开始部分定义了我们将在什么输入范围上进行操作,然后在输入字符串中有一个std::regex表示应该匹配的内容或不应该匹配的内容。匹配策略的类型由last参数给出。

  • 1->给我我在正则表达式和
  • 中定义的内容
  • -1->给我基于正则表达式不匹配的内容。

  • 因此,既然我们了解了迭代器,我们就可以std::将 token 从迭代器复制到我们的目标,即 std::vectorstd::string。而且由于我们不知道我们将拥有多少列,我们将使用 std::back_inserter作为目标。这将添加我们从 std::sregex_token_iterator获得的所有 token ,并将其附加到我们的 std::vector<std::string>>中。我们有多少列并不重要。

    好。这样的声明可能看起来像
    std::copy(                          // We want to copy something
    std::sregex_token_iterator // The iterator begin, the sregex_token_iterator. Give back first token
    (
    line.begin(), // Evaluate the input string from the beginning
    line.end(), // to the end
    re, // Add match a semicolon
    -1 // But give me back not the comma but everything else
    ),
    std::sregex_token_iterator(), // iterator end for sregex_token_iterator, last token + 1
    std::back_inserter(cp.columns) // Append everything to the target container
    );

    现在我们可以了解此复制操作的工作原理。

    下一步。我们想从文件中读取。文件内容也包含某种相同的数据。相同的数据是行。

    如上所述,我们可以迭代相似的数据。是文件输入还是其他。为此,C++具有 std::istream_iterator。这是一个模板,作为模板参数,它获取应读取的数据类型,作为构造函数参数,它获取对输入流的引用。没关系,无论输入流是 std::cin还是 std::ifstreamstd::istringstream。各种流的行为都相同。

    而且由于没有SO的文件,因此我使用(在下面的示例中) std::istringstream来存储输入的csv文件。但是当然您可以通过定义 std::ifstream testCsv(filename)打开文件。没问题。

    使用 std::istream_iterator,我们遍历输入并读取相似的数据。在我们的案例中,一个问题是我们要遍历特殊数据而不是某些内置数据类型。

    为了解决这个问题,我们定义了一个Proxy类,它为我们做内部工作(我们不希望知道如何封装在代理中)。在代理中,我们覆盖类型转换运算符,以将结果转换为 std::istream_iterator的预期类型。

    最后一步。 std::vector具有范围构造器。在定义 std::vector类型的变量时,还可以使用许多其他构造函数。但是出于我们的目的,此构造函数最合适。

    因此,我们定义了一个变量csv并使用其范围构造函数,并为其指定了范围的开始和范围的结束。并且,在我们的特定示例中,我们使用 std::istream_iterator的begin和end迭代器。

    如果我们将以上所有内容结合在一起,则读取完整的CSV文件是一回事,这是通过调用其构造函数定义的变量。

    请查看结果代码:
    #include <iostream>
    #include <sstream>
    #include <fstream>
    #include <string>
    #include <vector>
    #include <iterator>
    #include <regex>
    #include <algorithm>

    std::istringstream testCsv{ R"(Ketchup;98;24;2;Processed
    Fries;10;20;2;Processed
    Meat;10;20;2;Processed)" };


    // Define Alias for easier Reading
    using Columns = std::vector<std::string>;
    using CSV = std::vector<Columns>;


    // Proxy for the input Iterator
    struct ColumnProxy {
    // Overload extractor. Read a complete line
    friend std::istream& operator>>(std::istream& is, ColumnProxy& cp) {

    // Read a line
    std::string line; cp.columns.clear();
    std::getline(is, line);

    // The delimiter
    const std::regex re(";");

    // Split values and copy into resulting vector
    std::copy(std::sregex_token_iterator(line.begin(), line.end(), re, -1),
    std::sregex_token_iterator(),
    std::back_inserter(cp.columns));
    return is;
    }

    // Type cast operator overload. Cast the type 'Columns' to std::vector<std::string>
    operator std::vector<std::string>() const { return columns; }
    protected:
    // Temporary to hold the read vector
    Columns columns{};
    };


    int main()
    {
    // Define variable CSV with its range constructor. Read complete CSV in this statement, So, one liner
    CSV csv{ std::istream_iterator<ColumnProxy>(testCsv), std::istream_iterator<ColumnProxy>() };

    // Print result. Go through all lines and then copy line elements to std::cout
    std::for_each(csv.begin(), csv.end(), [](Columns& c) {
    std::copy(c.begin(), c.end(), std::ostream_iterator<std::string>(std::cout, " ")); std::cout << "\n"; });
    }

    我希望解释的内容足够详细,以使您了解使用现代C++可以做什么。

    此示例基本上不关心源文本文件中有多少行和多少列。它会吃掉一切。

    当然,您可以将字符串转换为所需的任何字符串。

    关于c++ - 从文件中逐字读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58661770/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com