gpt4 book ai didi

c++ - 如何读取包含不同数字行的文件

转载 作者:行者123 更新时间:2023-11-28 00:40:21 25 4
gpt4 key购买 nike

我正在尝试读取一个数据文件,大约 2000 行,该文件看起来像

1.1 1.2 1.3 1.4 1.5
1.6 1.7 1.8 1.9
2.0
2.1 2.2 2.3 2.4 2.5

其实有一个空白(white space)和1.3/1.7在同一列

我将其设置为存储的方式是一个结构 vector ,其中

struct num
{
double d1, d2, d3, d4, d5;
};

我想要实现的是

num A;
vector<num> data
for (int i = 0; i < 4; i++)
{
File >> A.d1 >> A.d2 >> A.d3 >> A.d4 >> A.d5;
data.push_back(A);
}

并找到识别第二行空白并存储 d1=1.6、d2=0、d3=1.7 等的逻辑。第三行是 d1=2.0 和 d2、d3、d4, d5=0如果可能的话,我只是对如何测试/获取实现它的逻辑感到困惑我在 C++ VS2010在查看第一个答案后认为我应该提供更多信息,文件中的每一行都属于一颗卫星,每个数字代表对特定波长的观察,因此如果它是空白的,则意味着它没有对该波长的观察。

所以详细说明,第一行代表卫星 1 对所有 5 个波长都有观测,第二行代表卫星 2 并且对波长 1、3、4、5 有观测而没有对波长 4 进行观测。

这就是为什么我试图将它分成每一行作为一个单独的结构,因为每一行都是一个单独的卫星

最佳答案

观察您的数据:

  • 每个数据点都按以下模式存储:数据、空间。
  • 如果数据点不存在,则用空格表示,除非它是最后一个不存在的数据点,所有其他输出都被截断为换行符。

这是我想出的:

#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <sstream>
#include <iomanip>
#include <cctype>
using namespace std;

//note all the lines are stored WITH newlines at the end of them.
//This is merely an artifact of the methodology I am using,
//as the newline is a flag that truncates output (as per your problem)
vector<string> preparse_input(const std::string& filename) {
vector<string> lines;

ifstream ifile;

ifile.open(filename.c_str(), ios::in);
if (!ifile.is_open()) {
exit(1);
}

string temp, chars, line;
char ch;

while(getline(ifile, temp)) {
temp += "\n";//getline removes the newline: because we need it, reinsert it
istringstream iss(temp);

//first read in the line char by char
while(iss >> noskipws >> ch) {
chars += ch;
}

bool replaced_newline = false;
int nargs = 0;

//I could have used iterators here, but IMO, this way is easier to read. Modify if need be.
for (int i = 0; i < chars.size(); ++i) {
if (isdigit(chars[i]) && chars[i+1] == ' ') {
nargs += 1;
}
else if(isspace(chars[i]) && isspace(chars[i+1])) {
if (chars[i+1] == '\n') {
replaced_newline = true;
}
//this means that there is no value set
//hence, set the value to 0 for the value part:
chars[i+1] = '0';
line += chars[i];
++i;//now, skip to the next character since 1 is for spacing, the other is for the value
nargs += 1;
}

//now rebuild the line:
line += chars[i];

if(isdigit(chars[i]) && chars[i+1] == '\n') {
nargs += 1;
//check nargs:
for (int i = nargs; i < 5; ++i) {
line += " 0";
nargs += 1;
}
}

if (replaced_newline) {
line += '\n';
}
replaced_newline = false;
}

lines.push_back(line);
chars.clear();
line.clear();
}
ifile.close();

return lines;
}

//this way, it's much easier to adapt to any type of input that you may have
template <typename T>
vector< vector<T> > parse_input (const vector<string>& lines) {
vector< vector<T> > values;
T val = 0;

for(vector<string>::const_iterator it = lines.begin(); it != lines.end(); ++it) {
vector<T> line;
istringstream iss(*it);
string temp;

while(getline(iss, temp, ' ')) {
if (istringstream(temp) >> val) {
line.push_back(val);
}
else {
line.push_back(0);//this is the value that badly parsed values will be set to.
//you have the option of setting it to some sentinel value, say -1, so you can go back and correct it later on, if need be. Depending on how you want to treat this error - hard or soft (stop program execution vs adapt and continue parsing), then you can adapt it accordingly
//I opted to treat it as a soft error but without a sentinel value - so I set it to 0 (-1 as that is probably more applicable in a general case), and informed the user that an error occurred
//The flipside of that is that I could have treated this as a hard error and have `exit(2)` (or whatever error code you wish to set).
cerr << "There was a problem storing:\"" << temp << "\"\n";
}
}
values.push_back(line);
}
return values;
}

int main() {
string filename = "data.dat";
vector<string> lines = preparse_input(filename);

vector < vector<double> > values = parse_input<double>(lines);

for (int i = 0; i < values.size(); ++i) {
for (int j = 0; j < values[i].size(); ++j) {
cout << values[i][j] << " ";
}
cout << endl;
}

return 0;
}

总而言之,我通过逐个字符地读取每一行来分解字符串,然后通过用 0 替换空格来重建每一行以便于解析。为什么?因为没有这样的值,就无法判断存储或跳过了哪个参数(使用默认的 ifstream_object >> type 方法)。

这样,如果我随后使用 stringstream 对象来解析输入,我就可以正确地确定设置或未设置的参数;然后,存储结果,一切都很好。这就是您想要的。

并且,将其用于以下数据:

1.1 1.2 1.3 1.4 1.5
1.6 1.7 1.8 1.9
2.0
2.0
2.1 2.2 2.3 2.4 2.5
2.1 2.4

给你输出:

1.1 1.2 1.3 1.4 1.5
1.6 0 1.7 1.8 1.9
2 0 0 0 0
2 0 0 0 0
2.1 2.2 2.3 2.4 2.5
2.1 0 0 2.4 0

注意:第 3 行有 8 个空格(1 个用于无数据,1 个用于间距)。第 4 行是原始数据中的行。第 6 行包含 5 个空格(遵循引用的模式)。

最后,让我说这是迄今为止我遇到过的最疯狂的数据存储方法之一。

关于c++ - 如何读取包含不同数字行的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19215891/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com