【问题标题】:Reading only the formatted data in a file that has formatted and unformatted data using c++使用c ++仅读取具有格式化和未格式化数据的文件中的格式化数据
【发布时间】:2018-12-29 06:40:27
【问题描述】:

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

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

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


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

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

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 to char。

第一种方法更好,我只是不知道如何实现检查以仅读取行中的变量,如果该行是格式化的。

【问题讨论】:

    标签: c++


    【解决方案1】:

    我会建议这样的事情:

    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();
    

    【讨论】:

    • hmm 我收到此错误 main.cpp: In function 'int main()': main.cpp:92:39: error: variable 'std::stringstream iss' has initializer 但不完整类型 std ::stringstream iss(line);
    • 确实会有所作为
    • 我现在遇到的问题是我的结构中的变量不是字符串。这种方法似乎要求它们是字符串......由于其他原因,我不能将它们定义为结构中的字符串,它被太多其他东西使用了
    • 一旦你解析了一个项目,你可以很容易地将它从“字符串”转换成你的小心脏想要的任何东西;)例如,std::stod 将一个字符串转换为一个双精度。
    【解决方案2】:

    您可以通过读取每一行并从该行创建一个stringstream 并验证该行以"keyword" 开头并且它包含每个剩余项目,从而轻松地仅找到您感兴趣的格式化行。由于您使用的是stringstream,因此您无需将所有值读取为string,您只需将值读取为所需的type。如果该行以END 开头,则您已阅读完毕,只需break;,否则如果第一个单词不是"keyword",则只需从文件中读取下一行并重试。

    ifstreamf 身份打开到您的数据文件后,您可以执行以下操作来定位和解析所需数据:

        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
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-19
      • 2014-06-12
      • 2012-08-13
      • 1970-01-01
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 2017-08-06
      相关资源
      最近更新 更多