【问题标题】:Reading two columns in CSV file in c++在 C++ 中读取 CSV 文件中的两列
【发布时间】:2015-07-22 18:42:48
【问题描述】:

我有一个两列形式的 CSV 文件:姓名、年龄

为了读取和存储信息,我这样做了

struct person
{
    string name;
    int age;
}
person record[10];
ifstream read("....file.csv");

但是,当我这样做时

read >> record[0].name;
read.get();
read >> record[0].age;

read>>name 给了我整行而不是名字。我怎样才能避免这个问题,以便我可以将整数读入年龄?

谢谢!

【问题讨论】:

    标签: c++ csv


    【解决方案1】:

    read>>name 给了我整行而不是名字。我怎样才能避免这个问题,以便我可以将整数读入年龄?

    read >> name 会将所有内容读入name,直到遇到空格。

    如果您有一个没有空格的逗号分隔行,则将整行读入name 是有意义的。

    您可以使用std::getline 将整行读取为一个字符串。然后使用各种方法标记std::string

    解决标记std::string 的示例 SO 帖子:

    How do I tokenize a string in C++?
    c++ tokenize std string
    Splitting a C++ std::string using tokens, e.g. ";"

    【讨论】:

      【解决方案2】:

      您也许可以为此使用字符串流,但老实说,我不会相信这一点。 如果我是你,我会编写一个小函数,将整行读入一个字符串,然后在字符串中搜索分隔符。前面的所有内容都是第一列,第二列后面的所有内容。使用 C++ 提供的字符串操作,您可以在变量中移动这些部分(如果需要,可以将它们转换为正确的类型)。 我写了一个用于 CSV 解析的小型 C++ 库,也许看看它对你有帮助。你可以在GitHub找到它。

      编辑: 在此 Gist 中,您可以找到 parsing function

      【讨论】:

        【解决方案3】:

        你可以先用std:getline读整行,然后通过std::istringstream解析(必须#include <sstream>),like

        std::string line;
        while (std::getline(read, line)) // read whole line into line
        {
            std::istringstream iss(line); // string stream
            std::getline(iss, record[0].name, ','); // read first part up to comma, ignore the comma
            iss >> record[0].age; // read the second part
        }
        

        下面是一个完整的通用示例,它标记了一个 CSV 文件 Live on Ideone

        #include <iostream>
        #include <fstream>
        #include <sstream>
        #include <string>
        #include <vector>
        
        int main()
        {
            // in your case you'll have a file
            // std::ifstream ifile("input.txt");
            std::stringstream ifile("User1, 21, 70\nUser2, 25,68"); 
        
            std::string line; // we read the full line here
            while (std::getline(ifile, line)) // read the current line
            {
                std::istringstream iss{line}; // construct a string stream from line
        
                // read the tokens from current line separated by comma
                std::vector<std::string> tokens; // here we store the tokens
                std::string token; // current token
                while (std::getline(iss, token, ','))
                {
                    tokens.push_back(token); // add the token to the vector
                }
        
                // we can now process the tokens
                // first display them
                std::cout << "Tokenized line: ";
                for (const auto& elem : tokens)
                    std::cout << "[" << elem << "]";
                std::cout << std::endl;
        
                // map the tokens into our variables, this applies to your scenario
                std::string name = tokens[0]; // first is a string, no need for further processing
                int age = std::stoi(tokens[1]); // second is an int, convert it
                int height = std::stoi(tokens[2]); // same for third
                std::cout << "Processed tokens: " << std::endl;
                std::cout << "\t Name: " << name << std::endl;
                std::cout << "\t Age: " << age << std::endl;
                std::cout << "\t Height: " << height << std::endl;
            }
        }
        

        【讨论】:

        • 非常感谢vsoftco。你介意再解释一下吗?假设我有三列,字符串名称、整数年龄、整数高度。代码会是什么样子?
        • @Dinosaur getline 部分只是“吃掉”流直到逗号,然后忽略逗号。在这种情况下,您需要另一个 getline,将读取的字符串转换为带有std::stoi 的整数,并记录结果。最后,最后一次读取可以是iss &gt;&gt; record[0].height。一般情况类似于:while(getline(token,',')){ // process the string token}
        • 您好 vsoftco,对不起,我没有得到令牌部分。您介意用完整的解决方案代替您当前的答案吗?非常感谢!
        • @Dinosaur 我将示例添加到答案中,因为我意识到其他人可能会觉得它有用。
        • 非常感谢您的帮助。我只是将我的代码作为一个单独的问题发布,因为我不能将所有内容都放在此处作为评论。你介意帮帮我吗?我不知道为什么它失败了。
        猜你喜欢
        • 2020-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-23
        • 2021-11-19
        相关资源
        最近更新 更多