c++ 解析.csv文件(全)

c++ 解析csv文件 

一、项目要求:

(1) 这个程序需要做到将csv文件的内容读取进来解析,并将每一个联系人的数据进行打印;
(2) 用户输入排序的属性key,将排序完成的结果打印出来;
(3) 能够对错误格式的文件进行检测;
(4) 能够对错误的数据进行容错;
(5) 文件编码格式不限,输出为UTF8格式

二、分析问题

1.问题1对与csv文件的读取,要如何读取,想到可以对文件进行读操作的文件方法函数,对文件读取之后怎么去进行将每一行的数据进行剪切成每一个主题。剪切后的数据如何保持,是用二维数组,还是用结构体(分析得出为了后面的任务方便进行,还是用结构体来存储数据是最好的)

2.问题二 属性key的排序,对于排序,比如 用id ,age 等数字型的数据项进行排序,其中的排序是如何实现?是升序还是降序?这个都要了解。排序好了之后怎么再次打印出来,个用户查看等

3.要考虑到csv文件的错误格式有哪些,什么场景下会比较容易产生错误的格式文件,又如何对其进行检测,检测完之后如何让用户更改过来等。

4.问题四 对错误的数据进行容错,首先要知道了解,数据的错误又那些?其中我下面的代码实现中实现两个常见的错误数据例如 用分号注释的字符 "****",或 ","这些,csv文件有编码格式可能不符合,导致解析到数据乱码

三、代码实现

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include<algorithm>

#include <Windows.h>
using namespace std;

struct student {          //成员结构体

	int id;
	string name;
	int age;
	string hobby;


};
class new_csv {                    //创建一个功能类

public:

	void output(vector<student>& vectorclient);  //排序输出函数

	int examine(int* num, int& bit);
	char* Fault(string sum);


};

std::wstring utf8ToUtf16(const std::string& utf8String)
{
	std::wstring sResult;
	int nUTF8Len = MultiByteToWideChar(CP_UTF8, 0, utf8String.c_str(), -1, NULL, NULL);
	wchar_t* pUTF8 = new wchar_t[nUTF8Len + 1];

	ZeroMemory(pUTF8, nUTF8Len + 1);
	MultiByteToWideChar(CP_UTF8, 0, utf8String.c_str(), -1, pUTF8, nUTF8Len);
	sResult = pUTF8;
	delete[] pUTF8;

	return sResult;
}
LPCWSTR stringToLPCWSTR(std::string orig)
{
	size_t origsize = orig.length() + 1;
	const size_t newsize = 100;
	size_t convertedChars = 0;
	wchar_t* wcstring = (wchar_t*)malloc(sizeof(wchar_t) * (orig.length() - 1));
	mbstowcs_s(&convertedChars, wcstring, origsize, orig.c_str(), _TRUNCATE);
	return wcstring;
}

std::string wstring2string(wstring wstr)
{
	string result;
	//获取缓冲区大小,并申请空间,缓冲区大小事按字节计算的  
	int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), NULL, 0, NULL, NULL);
	char* buffer = new char[len + 1];
	//宽字节编码转换成多字节编码  
	WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), buffer, len, NULL, NULL);
	buffer[len] = '\0';
	//删除缓冲区并返回值  
	result.append(buffer);
	delete[] buffer;
	return result;
}
char* UnicodeToUTF8(wchar_t* wszcString)
{
	int utf8Len = ::WideCharToMultiByte(CP_UTF8, NULL, wszcString, int(wcslen(wszcString)), NULL, 0, NULL, NULL);
	char* szUTF8 = new char[utf8Len + 1];    //给'\0'分配空间
	::WideCharToMultiByte(CP_UTF8, NULL, wszcString, int(wcslen(wszcString)), szUTF8, utf8Len, NULL, NULL);    //转换
	szUTF8[utf8Len] = '\0';

	return szUTF8;
}
std::string utf8ToUnicode(const char* route) {
	//return route;
	wstring wfilepath = utf8ToUtf16(route);
	return wstring2string(wfilepath);
}
std::string TCHAR2STRING(TCHAR* STR)
{
	int iLen = ::WideCharToMultiByte(CP_ACP, 0, STR, -1, NULL, 0, NULL, NULL);
	char* chRtn = new char[iLen * sizeof(char)];
	::WideCharToMultiByte(CP_ACP, 0, STR, -1, chRtn, iLen, NULL, NULL);
	std::string str(chRtn);
	return str;
}


//id的排序函数
bool sortid(const student& a, const student& b)
{
	if (a.id < b.id)
	{
		return true;

	}
	else {
		return false;
	}

}

//age排序函数

bool sortage(const student& a, const student& b)
{
	if (a.age < b.age)
	{
		return true;

	}
	else {
		return false;
	}

}

void  new_csv::output(vector<student>& vectorclient)   //排序输出函数
{

	for (vector<student>::iterator it = vectorclient.begin(); it != vectorclient.end(); it++)
	{
		::cout << "id: " << it->id << " name: " << it->name << " age: " << it->age << " hobby: " << it->hobby << endl;
	}

}
int new_csv::examine(int* num, int& bit)   //对输入文件格式进行判断是否有误
{
	for (int i = 1; i < bit - 1; i++)
	{
		if (num[i] == num[i + 1])
		{
			cout << "csv文件对应要求无误" << endl;
			return 0;

		}
		else
			cout << "请检查文件中是否有空格,或文件编写格式有问题,导致文件信息对应不上" << endl;
		return 0;
	}


}

char* new_csv::Fault(string linestr)
{
	char* sum;
	sum = (char*)malloc(100);
	int len_str = strlen(linestr.c_str());
	int k = 0;
	memset(sum, 0, 100);
	for (int j = 0; j < len_str; j++)
	{
		/*if (linestr[j] == '*')
		{
			linestr[j] = ',';
		}*/
		if (linestr[j] == '"' && linestr[j + 1] == '"')                  //对fgets到的数组结尾的换行符进行替换
		{
			sum[k] = linestr[j];
			k++;
			j = j + 1;
		}
		else if (linestr[j] == '"' && linestr[j + 1] != '"') {
		
				sum[k] = linestr[j + 1];
				k++;
				j = j + 1;
			
		}
		else {
			if (linestr[j] == ',' && linestr[j + 1] == '"' && linestr[j-1] =='"')
			{
				sum[k] = '*';
				k++;
			}
			else
			{
				sum[k] = linestr[j];
				
				k++;
			}
		}
	}
	return sum;

}
int main()
{

	ifstream infile("newfile.csv", ios::in);//infile来自fstream,ifstream为输入文件流(从文件读入)

	string linestr;
	int size_1[10] = { 0 };
	char* sum;
	char* Second_sum;
	int n1 = 1;
	new_csv pot;
	vector<student> vectorclient;
	int num = 0;
	string key;
	int k = 0;
	while (getline(infile, linestr)) 		//读入整行数据到linestr里
	{

		n1 = 1;                              //定义对一行中的 逗号分割的每一段进行计数用来判断存储的区域
		sum = pot.Fault(linestr);
		stringstream ss(sum);//来自sstream
		string str;

		if (num > 0)
		{	//实现只对数据写入vector ,不对标题写入,从而进行排序 
			//按照逗号分隔

			student client;

			while (getline(ss, str, ','))    //数据进行循环存储
			{
				
				int len = strlen(str.c_str());
				for (int j = 0; j < len;j++)
				{
					if (str[j] == '*')
					{
						str[j] = ',';
					}
				}
				
				//cout<<str<<endl;
				switch (n1)
				{
				case 1:
					//int intstr = atoi(str);
					//需先将string转成char*
					client.id = atoi(str.c_str());
					break;
				case 2:
					client.name = utf8ToUnicode(str.c_str());
					//client.name = utf8ToUnicode(char1);
					
					break;
				case 3:
					client.age = atoi(str.c_str());
					break;
				case 4:
					client.hobby = str;;// utf8ToUnicode()将一个字符串的UTF8编码转换成Unicode(UCS-2和UCS-4)编码.
					break;


				}
				n1++;

			}
			size_1[num] = n1;

			vectorclient.push_back(client);//每一行client数据都放到vectorclient中去
		}


		num++;
		free(sum);

	}
	pot.examine(size_1, num);    //对错误数据信息类型进行判断
	//未排序 
	::cout << "————csv文件中获取的信息如下————" << endl;
	//输出结果
	pot.output(vectorclient);

	cout << "注意两个有效key id age 请输入要排序的key:" << endl;

	cin >> key;

	if (key == "id")
	{
		sort(vectorclient.begin(), vectorclient.end(), sortid);
		::cout << "————id排序后的信息如下————" << endl;
		pot.output(vectorclient);

	}
	else if (key == "age")
	{

		sort(vectorclient.begin(), vectorclient.end(), sortage);
		::cout << "————age排序后的信息如下————" << endl;
		pot.output(vectorclient);
	}
	else {

		cout << "无输入选项,无法排序,原信息如下" << endl;
		pot.output(vectorclient);
	}

	return 0;
}

运行结果:

 excel(看到文件中乱码,因为设置了不支持utf-8的编码,所以乱码,更改编码可以直接再notepad++中打开更改就行)

vs运行界面(通过代码将utf-8中的编码格式转换为Unicode可以正常输出中文) 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值