如何读取具有不同数字行的文件
How can I read a file with lines of different number of numbers
我正在尝试读取一个大约 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
实际上有一个空白(空格(和 1.3/1.7 在同一列中
我将其设置为存储的方式是结构向量,其中
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行对satelittle 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++11 或者如果不是 Boost 正则表达式。
然后,可以使用以下函数将字符串拆分为标记。
std::vector<std::string> split(const std::string& input, const std::regex& regex) {
// passing -1 as the submatch index parameter performs splitting
std::sregex_token_iterator
first(input.begin(), input.end(), regex, -1),
last;
return std::vector<std::string>(first, last);
}
例如,假设您的数据位于"data.txt"中,我以这种方式使用它来获取值:
#include <iostream>
#include <fstream>
#include <string>
#include <regex>
#include <vector>
using namespace std;
std::vector<std::string> split(const string& input, const regex& regex) {
// passing -1 as the submatch index parameter performs splitting
std::sregex_token_iterator
first(input.begin(), input.end(), regex, -1),
last;
return vector<std::string>(first, last);
}
int main()
{
ifstream f("data.txt");
string s;
while (getline(f, s))
{
vector<string> values = split(s, regex("\s"));
for (unsigned i = 0; i < values.size(); ++i)
{
cout << "[" << values[i] << "] ";
}
cout << endl;
}
return 0;
}
这将给出以下结果:
[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]
请注意,第 4 行缺少一列,但那是因为我不太确定该行有多少空格。 如果您知道不超过 5 列,则可以在输出阶段进行更正。
希望这种方法对您有所帮助。
为什么不直接使用 std:vector
来保存浮点数数组。
要将新元素添加到您使用的向量中,请执行以下操作:
std::vector::p ush_back
当您阅读每个字符时,请查看它是数字还是句点。
如果是,请将其添加到std::string
,然后使用带有mystring.c_str()
的atof
作为参数将其转换为浮点数。
这也可能有助于将字符串转换为浮点数:
std::字符串到浮点数或双精度
因此,读入字符串,然后将浮点数推到向量,然后重复,跳过不是数字或句点的字符。
在行的末尾,你的向量有所有的浮点数,如果你想用自定义分隔符将它们连接到一个字符串中,你可以看看这个问题的答案:
std::矢量到字符串与自定义分隔符
- 如何在C++中确定文本文件中的元素是字符还是数字
- 使用fstream对txt文件中的数字进行循环
- 如何在 C++ 中将文件中的逗号分隔数字读取到数组中?
- 为什么当我输入较大的数字时,我的程序会到达文件末尾?
- 如何从也包含C++字母的文本文件中提取某些数字?
- 如何将 UTF-8 文本从文件转换为某个可以迭代的容器,并检查每个符号是否为C++字母数字?
- 从.txt文件中读取浮点型数字并在公式中使用它们
- 在 txt 文件中显示前两个数字的程序
- 尝试将数字写入二进制文件时引发异常
- 为什么我的程序在读取/写入文件时会删除最重要的数字?
- C++:从文件中读取字符串和整数,并获得最大数字
- 一个C++程序,用于在输入位数时输出具有特定位数的 .txt 文件中的所有数字
- 如何读取具有数字间隔的文本文件?C++
- 如何知道文本文件中的输入是否是 C++ 中的有效数字
- 如何删除文件中的数字,通过 c++ fstream 的
- 在c++中读取文件时,它如何自动将字符放入字符数组,将数字放入整数变量
- 如何从txt文件c++中提取括号之间的数字
- 在获取从文件到矢量的每一行之后,数字将被更改或销毁
- 如何将数字输出到文件中,所有数字都具有相同的精度
- 将数字文件读入数组,同时每1026个条目跳过前两个值