【C/C++学习】数据读入-格式3(二维表)


【C++学习】数据读入-格式2(多列)
掌握多列数据读入方法后,可通过改写代码从txt文件批量读入二维数据。

1. 功能概述

1.1 功能效果

需要读入多个二维数据表,但文件数据可能格式不对齐,或者存在非法字符、缺少数据,读入程序要具备数据检查功能。
在这里插入图片描述

1.2 使用方法

  1. 输入要求:每个表都有相同的维度,并且共用两个自变量x和y;
  2. 读入结果:有两种使用方法,看需。
#include "Map2DArray.h"//std,map,iostream,fstream

int main()
{
	map<string, double**> mapMath;
	Map2DArray Math(".\\math.txt", mapMath);

	int nHeader = Math.getNHeader();
	int rowInt = Math.getRowInt();
	int colInt = Math.getColInt();
	double *xInt = Math.getXInt();
	double *yInt = Math.getYInt();

	/* 使用方法1 */
	cout << "使用方法1:" << endl;
	for (int iHeader = 0; iHeader < 1; iHeader++) {
		cout << "f1(x,y)" << "\t";
		for (int i = 0; i < colInt; i++) {
			cout << yInt[i] << "\t";
		}
		cout << endl;
		for (int i = iHeader * rowInt; i < (iHeader + 1)*rowInt; i++) {
			cout << xInt[i - iHeader * rowInt] << "\t";
			for (int j = 0; j < colInt; j++) {
				cout << mapMath["f1(x,y)"][i][j] << "\t";
			}
			cout << endl;
		}

		cout << "f2(x,y)" << "\t";
		for (int i = 0; i < colInt; i++) {
			cout << yInt[i] << "\t";
		}
		cout << endl;
		for (int i = iHeader * rowInt; i < (iHeader + 1)*rowInt; i++) {
			cout << xInt[i - iHeader * rowInt] << "\t";
			for (int j = 0; j < colInt; j++) {
				cout << mapMath["f2(x,y)"][i][j] << "\t";
			}
			cout << endl;
		}
	}

	/* 使用方法2 */
	cout << "使用方法2:" << endl;
	Math.Disp();

	return 0;
}

2. 注意事项

  1. 如果文件中的数据存在科学计数法,只要将’E’或’e’加入判断即可,但我几乎没遇到这种类型;
    修改
  2. 也许有人想用多个具有不同维度的表,这会给数据检查带来困难,我一般把不同维度的表放在不同文件。

3. 详细代码

Map2DArray.h

/*
* Auther:	 sanfan66
*
* Date        | Change
*--------------------------------------------
* 230926   | <record>: None→Version 0.0a,Original finished
*                | (describe): Map2DArray needs input-file with a header in front of the data
*                | (describe): '\t'or' 'to separate the words
*                | !warning!: ~Map2DArray 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 Map2DArray {
public:
	Map2DArray(const char *path, map<string, double**>&map_name);
	~Map2DArray();
	int getNum(ifstream *file, const char *path);
	double getData(ifstream *file, const char *path);

	int getNHeader() const { return nHeader; };
	int getRowInt() const { return rowInt; };
	int getColInt() const { return colInt; };
	double *getXInt() const { return xInt; };
	double *getYInt() const { return yInt; };
	
	int isMathNumb(char MathNumb) const {
		return ((MathNumb - '0' > -EPS && MathNumb - '9' < EPS) || MathNumb == '.' || MathNumb == '-' || MathNumb == '+');
	}
	void Disp() const;

private:
	int nHeader;
	int rowData;
	int colData;
	int rowInt;
	int colInt;
	double *xInt ;
	double *yInt ;
	char **header_name;
	double **lines_data;
};


Map2DArray.cpp

#include "Map2DArray.h"

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

	xInt = new double[rowInt];
	yInt = new double[colInt];

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

	getData(&file, path);

	for (int i = 0; i < nHeader; i++) {
		map_name[header_name[i]] = &lines_data[i*rowInt];//!!lines_data[i*rowInt]是数据的地址,不是**
	}

	file.close();
}

Map2DArray::~Map2DArray() {
	/* 清理堆空间,new对应delete,new[]对应delete[] */
	delete[] xInt;
	xInt = nullptr;
	delete[] yInt;
	yInt = nullptr;

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

	for (int i = 0; i < nHeader*rowInt; i++) {
		delete[] lines_data[i];
		lines_data[i] = nullptr;
	}
	delete[] lines_data;
	lines_data = nullptr;
}

int Map2DArray::getNum(ifstream *file, const char *path) {
	/* 获取行数 */
	int indexHeader = 0;
	int indexRow = 0;
	int indexLines = 0;
	string one_line;
	while (file->peek() != EOF) {
		getline(*file, one_line);
		int indexCol = 0;//统计每行的列数

		char *buf = &one_line[0];
		char *one_line_char = nullptr;
		char *next_word_ptr = buf;
		while (*next_word_ptr != '\0') {		//取一行,每次以制表符或空格分隔取出一个词
			one_line_char = strtok_s(buf, "\t ", &next_word_ptr);

			if (one_line_char != nullptr) {		//连续的分隔符会返回空指针
				int isNumber = 0;
				for (unsigned i = 0; i < strlen(one_line_char); i++) {
					if (isMathNumb(one_line_char[i])) {
						isNumber++;
					}
				}
				if (isNumber == strlen(one_line_char)) {//是数字					
					if (indexCol == 0) {
						indexRow++;
					}
				}
				else {//是非数字字符
					if (indexCol == 0) {
						indexHeader++;
					}
					else {
						cout << path << "第" << indexLines + 1 << "行第" << indexCol + 1 << "个词有非数字字符(不包括表头)" << endl;
						system("Pause");
						exit(0);
					}
				}
				indexCol++;
			}
			buf = nullptr;
		}
		if (indexHeader == 1) {//使用第一行数据判断列数
			colData = indexCol;
		}
		else {
			if (indexCol > 0 && colData != indexCol) {		//跳过只有回车/空格的行
				cout << path << "第" << indexLines + 1 << "行数据个数=" << indexCol << ",而列数=" << colData << endl;
				system("Pause");
				exit(0);
			}
		}
		indexLines++;
	}

	if (indexHeader == 0) {
		cout << path << "没有表头" << endl;
		system("Pause");
		exit(0);
	}
	rowData = indexRow;
	nHeader = indexHeader;

	if (rowData% nHeader) {// %整数取余,/结果保留整数部分,同(int)
		cout << path << "数据列数/表头个数=" << rowData / nHeader << "余" << rowData % nHeader << endl;
		system("Pause");
		exit(0);
	}
	else {
		rowInt = rowData / nHeader;
		colInt = colData - 1;
	}

	return 0;
}

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

	int indexHeader = 0;
	int indexRow = 0;
	int indexUsefulLines = 0;//只统计有效的行
	string one_line;
	while (file->peek() != EOF) {
		getline(*file, one_line);
		int indexCol = 0;//统计每行的列数

		char *buf = &one_line[0];
		char *one_line_char = nullptr;
		char *next_word_ptr = buf;
		while (*next_word_ptr != '\0') {		//取一行,每次以制表符或空格分隔取出一个词
			one_line_char = strtok_s(buf, "\t ", &next_word_ptr);

			if (one_line_char != nullptr) {		//连续的分隔符会返回空指针
				/* 读表头和数据 */
				if (indexUsefulLines % (rowInt + 1) != 0) {
					if (indexCol == 0) {
						if (indexRow < rowInt) {
							xInt[indexRow] = atof(one_line_char);//读第一个表的自变量x
						}
					}
					else {
						lines_data[indexRow][indexCol - 1] = atof(one_line_char);//读入二维数据
						if (indexCol == colInt) {//找到一行的最后一个数
							indexRow++;
						}
					}
				}
				else {
					if (indexCol == 0) {
						strcpy_s(header_name[indexHeader], strlen(one_line_char) + 1, one_line_char);//读入表头
						indexHeader++;
					}
					else {
						if (indexUsefulLines == 0) {
							yInt[indexCol - 1] = atof(one_line_char);//读第一个表的自变量y
						}
					}
				}
				indexCol++;
			}
			buf = nullptr;
		}
		if (indexCol != 0) {
			indexUsefulLines++;
		}
	}

	return 0;
}

/* 使用方法2 */
void Map2DArray::Disp() const {
	for (int iHeader = 0; iHeader < nHeader; iHeader++) {
		cout << header_name[iHeader] << "\t";
		for (int i = 0; i < colInt; i++) {
			cout << yInt[i] << "\t";
		}
		cout << endl;
		for (int i = iHeader * rowInt; i < (iHeader + 1)*rowInt; i++) {
			cout << xInt[i - iHeader * rowInt] << "\t";
			for (int j = 0; j < colInt; j++) {
				cout << lines_data[i][j] << "\t";
			}
			cout << endl;
		}
	}

	return;
}


已知前提条件有: 1. 内容是一个0到65535的数值. 2. 对应的二维有很多个, 而且每个的ROW COUNT和COLUMN COUNT都不固定. 3. 原始数据文件格式 a. 原始文件是文本格式, 文本行与上相对应. b. 每行由多个单词构成,单词之间由空格及制符(TAB)的组合来分割. c. 第一行的单词用于定义COLUMN VALUE的命名 d. 从第二行开始, 每文本行对应二维的一行. 第一个单词定义ROW VALUE的命名.从第二个单词开始, 每个单词均由数字构成, 描述二维的内容. e. 空文本行二维格结束. 根据上面的格, 下面是原始数据: AAA BBB CCC DDD AAA 0 1 1 4 BBB 2 2 5 3 CCC 8 7 6 6 DDD 9 9 9 9 4. 输出格式要求: 生成C语言格式的描述. 包含ROW VALUE定义, COLUMN VALUE定义及二维数据结构.(根据上面的格, 下面是个生成的例子) #define ROW_AAA 0 #define ROW_BBB 1 #define ROW_CCC 2 #define ROW_DDD 3 #define ROW_COUNT 4 #define COLUMN_AAA 0 #define COLUMN_BBB 1 #define COLUMN_CCC 2 #define COLUMN_DDD 3 #define COLUMN_COUNT 4 static <type> nuiTableData_a[][COLUMN_COUNT] = { 0, 1, 1, 4, 2, 2, 5, 3, 8, 7, 6, 6, 9, 9, 9, 9 }; 5. 原始数据一定是正确的, 不必考虑对原始数据的严格分析判断 6. 根据原始数据得出ROW COUNT和COLUMN COUNT 7. COLUMN VALUE从0开始, 依次递增. 8. ROW VALUE的定义和COLUMN VALUE定义类似, 但需要进行压缩判断.如果两列内容相同, ROW VALUE值也应该一样. 例如原始数据: … PPP 0 0 1 1 2 RRR 1 2 2 1 5 QQQ 0 1 2 3 4 SSS 1 2 2 1 5 TTT 9 9 8 8 7 … 那么生成的结果应是: … #define ROW_PPP 10 #define ROW_RRR 11 #define ROW_QQQ 12 #define ROW_SSS ROW_RRR #define ROW_TTT 13 … 题目: 编写一个程序。 读取一个文本格文件, 并生成另一种格式的文件(C语言格式的H文件), 同时将格的行列索引(AAA, BBB, CCC…,即ROW VALUE, COLUMN VALUE)以C语言格式进行定义.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值