【C/C++学习】数据读入-格式2(多列)


【C/C++学习】数据读入-格式1
掌握基本读入方法后,下面从txt文件读入较为复杂的数据。

1. 功能概述

1.1 功能效果

需要读入多列数据,由于每行数据都是不同的人记录的,可能存在:

  1. 数据是完备的:只是有的用制表符分开,有的用空格,甚至有多个制表符或空格连着的情况,要去掉这些分隔符正确读入;
  2. 数据是完备的:只是有多余的回车/空格,不能把这些读进去;
  3. 数据不完整:某处少输或多输了数,要报错并报位置,不包括上一条;
  4. 数据填错了:如果数据有很多行,难免敲入其他字符,存在非数字的情况,要报错并报位置。
    效果

1.2 使用方法

  1. 输入要求:首行需保证为表头,手动也是可以操作的;
  2. 读入结果:每列数据存为一个指针数组,有三种使用方式,考虑到多次调用效率,劝你使用方法2。
#include "MapColumn.h"//std,map,iostream,fstream

int main()
{
	map<string, double*> mapMing;
	MapColumn Ming(".\\ming.txt", mapMing);
	/* 使用方法1 */
	cout <<"使用方法1:"<<endl;
	for (int i = 0; i < Ming.getSize(); i++) {
		cout << mapMing.at("星期")[i] << "\t";
		cout << mapMing.at("CSDN(小时)")[i] << "\t";
		cout << mapMing.at("Bil(小时)")[i] << "\t";
		cout << mapMing.at("DY(小时)")[i] << "\t" << endl;
	}
	/* 使用方法2 */
	cout << "使用方法2:" << endl;
	class takeHours {
	public:
		double *week;
		double *CSDN;
		double *Bil;
		double *DY;
		int row;
	} takeHoursMing{
		mapMing.at("星期"),
		mapMing.at("CSDN(小时)"),
		mapMing.at("Bil(小时)"),
		mapMing.at("DY(小时)"),
		Ming.getSize()
	};
	for (int i = 0; i < takeHoursMing.row; i++) {
			cout << takeHoursMing.week[i] << "\t" ;
			cout << takeHoursMing.CSDN[i] << "\t" ;
			cout << takeHoursMing.Bil[i] << "\t" ;
			cout << takeHoursMing.DY[i] << "\t" << endl;
	}
	/* 使用方法3 */
	cout << "使用方法3:" << endl;
	Ming.Disp();	

	return 0;
}

2. 注意事项

  1. 使用方法1编写方便,但是多次使用的话花费较长时间,使用方法3效率也高但不知道表头的名字,所以使用方法2通过map来映射;
  2. 要读懂程序需要结合上一篇文章,难点在于数据的检查,本程序有些情况未考虑,你可以基于此构造出更健全的程序。

3. 详细代码

MapColumn.h

/*
* Auther:	 sanfan66
* Date           | Change
*--------------------------------------------
* 230926         | <record>: None→Version 0.00,Original finished
*                | (describe): MapRow needs input-file with a header in front of the data
*                | (describe): '\t'or' 'to separate the words
*                | !warning!: ~MapRow may not called in some cases
*/
#pragma once
#include <fstream>//ifstream
#include <map>
#include <iostream>//cout
#include <string>//getline
#define EPS 1e-7

using namespace std;//map,string,ifstream

class MapColumn {
public:
	MapColumn(const char *path, map<string, double*>&map_name);
	~MapColumn();
	int getNum(ifstream *file, const char *path);
	double getData(ifstream *file, const char *path);
	int getSize() const {
		return rowData;
	}
	void Disp() const;
private:
	int nHeader;
	int rowData;
	char **header_name;
	double **lines_data;
};

MapColumn.cpp

#include "MapColumn.h"

MapColumn::MapColumn(const char *path, map<string, double*>&map_name) {
	/* 打开文件、读入行数、读取数据、赋值地址 */
	ifstream file;
	file.open(path, ios::in);
	if (!file.is_open()) {
		cout << path << "无法打开" << endl;
		system("Pause");
		exit(0);
	}

	getNum(&file, path);

	header_name = new char*[nHeader];
	lines_data = new double*[nHeader];
	for (int i = 0; i < nHeader; i++) {
		header_name[i] = new char[100];
		lines_data[i] = new double[rowData];
	}

	getData(&file, path);

	for (int i = 0; i < nHeader; i++) {
		map_name[header_name[i]] = lines_data[i];
	}

	file.close();
}

MapColumn::~MapColumn() {
	/* 清理堆空间,new对应delete,new[]对应delete[] */
	for (int i = 0; i < nHeader; i++) {
		delete[] header_name[i];
		header_name[i] = nullptr;
		delete[] lines_data[i];
		lines_data[i] = nullptr;
	}
	delete[] header_name;
	header_name = nullptr;
	delete[] lines_data;
	lines_data = nullptr;
}

int MapColumn::getNum(ifstream *file, const char *path) {
	/* 获取维度 */
	int indexHeader = 0;
	int indexData = 0;
	int indexLines = 0;
	string one_line;
	while (file->peek() != EOF) {
		getline(*file, one_line);

		int isEnter = 1;//检查读取的行是否只有回车
		int isSpace = 1;//检查读取的行是否只有空格
		int nHeaderCheck = 0;//检查表头的个数与数据个数是否相等

		char *buf = &one_line[0];
		char *one_line_char = nullptr;
		char *next_word_ptr = buf;
		while (*next_word_ptr != '\0') {		//取一行,每次以制表符或空格分隔取出一个词
			isEnter = 0;//不是回车
			one_line_char = strtok_s(buf, "\t ", &next_word_ptr);
			if (one_line_char != nullptr) {		//连续的分隔符会返回空指针
				isSpace = 0;//不是空格
				/* 检查表头的个数和数据的个数是否一致,及数据是否含有非法字符 */
				switch (indexLines) {
				case 0: {	//第一行默认为表头
					indexHeader++;
					int HeaderIsNum = 0;	
					for (unsigned i = 0; i < strlen(one_line_char); i++) {
						if ((one_line_char[i] - '0' > -EPS && one_line_char[i] - '9' < EPS)) {
							HeaderIsNum++;
						}
					}
					if (HeaderIsNum == strlen(one_line_char)) {
						cout << path << "第" << indexHeader << "列是否缺少表头" << endl;
						system("Pause");		//提示但不终止
					}
					break;
				}
				default:	//第二行及以上默认为数据
					nHeaderCheck++;	
					for (unsigned i = 0; i < strlen(one_line_char); i++) {
						if (!((one_line_char[i] - '0' > -EPS && one_line_char[i] - '9' < EPS ) || one_line_char[i]=='.')) {
							cout << path << "第" << indexLines + 1 << "行第"<< nHeaderCheck <<"个数据为非数据符号" << endl;
							system("Pause");
							exit(0);
						}
					}
					break;
				}
			}
			buf = nullptr;
		}
		
		if (indexLines > 0 && isEnter == 0 && isSpace == 0) {
			indexData++;
			if (nHeaderCheck != indexHeader) { 
				cout << path << "第" << indexLines + 1 << "行表头个数="<< indexHeader <<",数据个数="<< nHeaderCheck << endl;
				system("Pause");
				exit(0);
			}
		}
		indexLines++;
	}
	rowData = indexData;
	nHeader = indexHeader;
	return 0;
}

double MapColumn::getData(ifstream *file, const char *path) {
	/* 读取数据 */
	file->clear();
	file->seekg(0, ios::beg);

	int indexData = 0;
	int indexLines = 0;
	string one_line;
	while (file->peek() != EOF) {
		getline(*file, one_line);
		int isEnter = 1;
		int isSpace = 1;
		int indexHeader = 0;

		char *buf = &one_line[0];
		char *one_line_char = nullptr;
		char *next_word_ptr = buf;
		while (*next_word_ptr != '\0') {		//取一行,每次以制表符或空格分隔取出一个词			
			isEnter = 0;
			one_line_char = strtok_s(buf, "\t ", &next_word_ptr); 
			if (one_line_char != nullptr) {		//连续的分隔符会返回空指针				
				isSpace = 0;
				switch (indexLines) {
				case 0: {	//第一行默认为表头
					strcpy_s(header_name[indexHeader], strlen(one_line_char) + 1, one_line_char);	
					break;
				}
				default:	//第二行及以上默认为数据					
					lines_data[indexHeader][indexData] = atof(one_line_char);			
					break;
				}
				indexHeader++;
			}
			buf = nullptr;
		}

		if (indexLines > 0 && isEnter == 0 && isSpace == 0) {
			indexData++;			
		}
		indexLines++;
	}
	return 0;
}

/* 使用方法3 */
void MapColumn::Disp() const{
	for (int i = 0; i < nHeader; i++) {
		cout << header_name [i]<<"\t";
	}
	cout << endl;
	for (int i =0 ; i< rowData; i++) {
		for (int j = 0; j < nHeader; j++) {
			cout << lines_data[j][i] << "\t" ;
		}
		cout<< endl;
	}
	return ;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值