我有一个数据文件,该文件的开头和结尾处都有未知数量的未格式化且不需要的数据。但是,在中间,数据是经过精确格式化的,第一列始终以几个关键字之一开头。我想跳到这一部分并读入数据,将每一列分配给一个变量。如果没有开始和结束的“垃圾”文本,这将很简单。
这是简单的示例问题。在我的真实代码中,每个变量都是结构的一部分。我认为这无关紧要,但是请以防万一...
这是我的文本文件,我希望所有以关键字开头的行,并且希望将所有列分配给变量
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。
第一个方法更好,我只是不知道如何实现只在变量行中读取变量的检查。
答案 0 :(得分:3)
我建议这样的事情:
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
仔细检查一下,如果还有其他问题,请告诉我。