使用C ++仅读取文件中已格式化和未格式化数据的格式化数据

时间:2018-12-29 06:40:28

标签: c++

我有一个数据文件,该文件的开头和结尾处都有未知数量的未格式化且不需要的数据。但是,在中间,数据是经过精确格式化的,第一列始终以几个关键字之一开头。我想跳到这一部分并读入数据,将每一列分配给一个变量。如果没有开始和结束的“垃圾”文本,这将很简单。

这是简单的示例问题。在我的真实代码中,每个变量都是结构的一部分。我认为这无关紧要,但是请以防万一...

这是我的文本文件,我希望所有以关键字开头的行,并且希望将所有列分配给变量


REMARK: this should be simpler
REMARK: yes, it should
REMARK: it is simple, you just don't see it yet
Comment that doesn't start with REMARK
keyword aaa 1 bbb 1 1.2555  O
keyword aaa 1 bbb 2 2.2555  H
keyword aaa 1 bbb 3 3.2555  C
keyword aaa 1 bbb 4 4.2555  C
END
Arbitrary garbage texts

如果没有随机评论,我可以使用

int main{
    string filename = "textfile.pdb";
    string name1,name2,name3;
    int int1, int2;
    double number;

    ifstream inFile;
    inFile.open(filename.c_str());

    while (inFile.good())
    {
        inFile >> keyword >> name1 >>  
        int1>>name2>>int2>>number>>name3;
    }
    inFile.close();
}

我尝试使用

解决此问题
while (getline(inFile,line))

此方法让我查看该行,并检查其中是否包含“关键字”。但后来我无法使用第一种方法的便捷格式化输入。我需要解析字符串,这在c ++中似乎很棘手。我尝试使用sscanf,但是它抱怨str变成char。

第一个方法更好,我只是不知道如何实现只在变量行中读取变量的检查。

2 个答案:

答案 0 :(得分:3)

我建议这样的事情:

Parsing text file in C++

string name,age,salary,hoursWorked,randomText;
ifstream readFile("textfile.txt");

while(getline(readFile,line))   {
    stringstream iss(line);
    getline(iss, name, ':');
    getline(iss, age, '-');
    getline(iss, salary, ',');
    getline(iss, hoursWorked, '[');
    getline(iss, randomText, ']');
}
readFile.close();

答案 1 :(得分:2)

通过阅读每一行并从该行创建一个stringstream并验证该行以"keyword"开头并包含其余所有内容,可以轻松地仅找到所需的格式化行。由于您使用的是stringstream,因此不需要将所有值都读取为string,您只需将值读取为所需的type。如果该行以END开头,那么您已经读完了break;,否则,如果第一个单词不是"keyword",则只需从文件中读取下一行,然后重试。

ifstream的格式打开f到数据文件后,您可以执行以下操作找到并解析所需的数据:

    while (getline (f, line)) {         /* read each line */
        int aval, bval;                 /* local vars for parsing line */
        double dblval;
        std::string kw, a, b, ccode;
        std::stringstream s (line);     /* stringstream to parse line */
        /* if 1st word not keyword, handle line appropriately */
        if ((s >> kw) && kw != "keyword") {
            if (kw == "END")            /* done with data */
                break;
            continue;                   /* otherwise get next line */
        }   /* read/validate all other data values */
        else if ((s >> a) && (s >> aval) && (s >> b) && (s >> bval) &&
            (s >> dblval) && (s >> ccode))
            std::cout << kw << " " << a << " " << aval << " " << b <<
                    " " << bval << " " << dblval << " " << ccode << '\n';
        else {  /* otherwise invalid data line */
            std::cerr << "error: invalid data: " << line;
            continue;
        }
    }

(仅将所需值输出到stdout,您可以根据需要使用它们)

在一个简短的示例中将其完全与数据一起使用,您可以执行以下操作:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

int main (int argc, char **argv) {

    std::string line;   /* string to hold each line */

    if (argc < 2) {     /* validate at least 1 argument given */
        std::cerr << "error: insufficient input.\n"
                    "usage: " << argv[0] << " filename\n";
        return 1;
    }

    std::ifstream f (argv[1]);   /* open file */
    if (!f.is_open()) {     /* validate file open for reading */
        perror (("error while opening file " + 
                std::string(argv[1])).c_str());
        return 1;
    }

    while (getline (f, line)) {         /* read each line */
        int aval, bval;                 /* local vars for parsing line */
        double dblval;
        std::string kw, a, b, ccode;
        std::stringstream s (line);     /* stringstream to parse line */
        /* if 1st word not keyword, handle line appropriately */
        if ((s >> kw) && kw != "keyword") {
            if (kw == "END")            /* done with data */
                break;
            continue;                   /* otherwise get next line */
        }   /* read/validate all other data values */
        else if ((s >> a) && (s >> aval) && (s >> b) && (s >> bval) &&
            (s >> dblval) && (s >> ccode))
            std::cout << kw << " " << a << " " << aval << " " << b <<
                    " " << bval << " " << dblval << " " << ccode << '\n';
        else {  /* otherwise invalid data line */
            std::cerr << "error: invalid data: " << line;
            continue;
        }
    }
    f.close();
}

示例输入文件

$ cat dat/formatted_only.txt
REMARK: this should be simpler
REMARK: yes, it should
REMARK: it is simple, you just don't see it yet
Comment that doesn't start with REMARK
keyword aaa 1 bbb 1 1.2555  O
keyword aaa 1 bbb 2 2.2555  H
keyword aaa 1 bbb 3 3.2555  C
keyword aaa 1 bbb 4 4.2555  C
END
Arbitrary garbage texts

使用/输出示例

$ ./bin/sstream_formatted_only dat/formatted_only.txt
keyword aaa 1 bbb 1 1.2555 O
keyword aaa 1 bbb 2 2.2555 H
keyword aaa 1 bbb 3 3.2555 C
keyword aaa 1 bbb 4 4.2555 C

仔细检查一下,如果还有其他问题,请告诉我。