从冒号分隔的文件中提取信息-C++

Extract information from a colon delimited file - C++

本文关键字:提取 信息 -C++ 文件 分隔      更新时间:2023-10-16

我正试图从冒号分隔的文件中将信息提取到类对象中。文件的每一行都以相同的格式设置。以下是文件的前几行:

s:Charles:Babbage:80:530213286:1133764834:mechanical engineering:3.8
e:Marissa:Meyer:37:549114177:53321:ceo:4456000
s:Alonzo:Church:92:586312110:1100539644:mathematics:4.0
e:Dana:Ulery:74:573811211:23451:engineer:124569

这是一个学校项目,目的是教我们关于阶级继承的知识。我们有一个基本班Person和两个儿童班Student和Employee。我们应该将学生的信息导入并存储到Student对象中,将employee对象中。我为每个类都有一个对象数组;我将学生排序到Student对象数组中,员工也是如此,此外,我还将所有人添加到people对象数组中。

我不知道该怎么做才能获得每一条带有分隔逗号的信息。现在我正在尝试使用.getline,但它似乎不起作用。如何使用此函数(或其他函数)将分隔符之间的信息提取到字符数组中?以下是到目前为止我对数据是针对员工的情况所做的:

ifstream fin;
char* tempImport;
tempImport = new char[50];
int* tempIntArray;
tempIntArray = new int[10];
double tempDouble;
int tempInt;
  // get the specifier of student or employee
  fin.getline(tempImport, ':');
  if(tempImport[0]=='e'){
     // get first name
     fin.getline(tempImport, ':');
     employees[employeeIndex].setFirstName(tempImport);
     allPeople[personIndex].setFirstName(tempImport);
     // get last name
     fin.getline(tempImport, ':');
     employees[employeeIndex].setFirstName(tempImport);
     allPeople[personIndex].setFirstName(tempImport);
     // get age
     fin.getline(tempImport, ':');
     employees[employeeIndex].setAge(tempImport[0] - 0);
     allPeople[personIndex].setAge(tempImport[0] - 0);
     // get SSN
     fin.getline(tempImport, ':');
     for(int i=0;i<9;i++){
        tempIntArray[i] = tempImport[i] - 0;
        }
     employees[employeeIndex].setSsn(tempIntArray);
     allPeople[personIndex].setSsn(tempIntArray);
     // get Employee ID
     fin.getline(tempImport, ':');
     for(int i=0;i<5;i++){
        tempIntArray[i] = tempImport[i] - 0;
        }
     employees[employeeIndex].setEmpID(tempIntArray);
     // get title
     fin.getline(tempImport, ':');
     employees[employeeIndex].setTitle(tempImport);
     // get salary
     fin >> tempDouble;
     employees[employeeIndex].setSalary(tempInt);
     employeeIndex++;
     personIndex++;
     }

调用ifstream::getline()时,似乎缺少一个参数。请参阅:http://www.cplusplus.com/reference/istream/istream/getline/

您需要该方法的3参数版本才能指定一个delimeter。当您调用2参数版本时,它将':'解释为流大小。(基本上,':'只是解析为冒号的ASCII代码,所以这个数字会被传入。您真正想要的streamsize是tempImport缓冲区的长度。)

然而,如果我可以建议(并且您的任务允许),std::getline()版本的函数可能会更好。(它允许您使用std::string而不是char*,这是一种更像C++的做事方式。此外,您不必担心您的输入是否大于缓冲区。)以下是相关文档:http://www.cplusplus.com/reference/string/string/getline/

所以基本上你可以这样做:

std::string tempImport;
std::getline(fin, tempImport, ':');

作为调试建议,您可以在每次调用getline()后打印tempImport(无论使用哪种)。在提交之前先把它们拿出来,但这些打印语句可以帮助您在此期间调试解析。

std::stderr << "getline(): " << tempImport << std::endl;

编辑:

关于下面的评论,我能够编译这个。(它没有做任何有用的事情,但表明std::getline()确实存在并编译。)它为您编译吗?

#include <fstream>
int main (int argc, char** argv)
{
        std::ifstream ifs;
        std::string str;
        std::getline(ifs, str, ':');
        return 0;
}

如果你能原谅我的话,你似乎学到了"面向对象编程"最糟糕的模仿之一(尽管这是一种安慰,但也是一种相当常见的模仿)。

就我个人而言,我认为我会写得有点不同。

我可能会从删除所有的setSalarysetTitle等开始。它们是OOP应该做的事情的可怕扭曲,在可读性方面损失了很多,而在封装方面却一无所获。

类不应该提供成员函数来操作类的所有成员,而应该提供一个更高级别的成员来从流中重构自己的实例。

当您获得数据时,您可能不想为您的人员/员工/学生数组创建单独的对象。相反,每个项目都将进入员工或学生的数组中。那么People将只是指向其他两个数组中的项目的指针数组。

至于读取数据的细节:就我个人而言,我可能会编写一个将:分类为空白的ctype类,然后只读取数据。不过,对于您的课程,您可能希望坚持使用getline

class Person { 
    virtual std::istream &read(std::istream &is);
    friend std::istream &operator>>(std::istream &is, Person &p) { 
        return p.read(is);
    }
};
class Student : public Person { 
    std::string first_name;
    std::string last_name;
    std::string age;
    std::string ssn;
    std::string ID;
    std::string title;
    std::string salary;
    virtual std::istream &read(std::istream &is) { 
        std::getline(is, first_name, ':');
        std::getline(is, last_name, ':');
        std::getline(is, age, ':');
        // ...
        return is;
    }
};

有了这些,从文件中读取数据通常会非常简单:

std::string t;
Employee e;
Student s;
while (std::getline(infile, t, ':'))
    if (t == "e") {
        infile >> e;
        Employees.push_back(e);
    }
    else if (t =="s") {
        infile >> s;
        Students.push_back(s);
    }