C++ CSV解析,可以获取任意[Y][X]位置内容

3092 人浏览 | 时间: 2016-02-26 09:35:55 | 作者: ooklasd

看到网上很多,都有解析CSV格式的,但是发现很多都是普通读取,没有进行转意符解析。有些是对空白处没有进行合法性判断的。所以自己写了一个可以定义起始位置,读取任意位置的类,类很简单。

使用前注意:


//mfc程序需要加预定义头
#include "stdafx.h"



使用方法如下:


CCSV csv(filename);
vector<SDetail> v;
if(csv.parse())
{
    //由第1行,第0列开始 
    csv.MoveTo(0,1);
    auto count = csv.count();
    for (unsigned int i = 0;i<count;i++)
	{
	    SDetail s;
	    s.name = csv[i][0];
	    s.type = csv[i][1];
	    s.unit = csv[i][2];
	    v.push_back(s);
	}
}
return v;





CSV.h


#pragma once
#include <map>
class CSVRow;
class CCSV
{
public:
	CCSV():_posX(0),_posY(0){};
	CCSV(std::string fileName);
	bool setFileName(std::string fileName){_fileName = fileName;};

	//转换分析
	bool parse(unsigned int lineMax = ~0);
	CSVRow operator[](unsigned int index);
	const std::string& getLastError()const;

	//设置起始位置,可以由设置第y行到第x列开始获取。
	void MoveTo(unsigned int x, unsigned int y);

	//从起始位置开始的行数
	unsigned int count()const;

	//所有行数
	unsigned int allCount()const {return _data.size();}
private:
	unsigned int _posX;
	unsigned int _posY;
	std::string _fileName;
	std::string _lastErrol;
	std::map<unsigned int,CSVRow> _data;
};

class CSVRow
{
	friend bool CCSV::parse(unsigned int lineMax);
public:
	CSVRow():_posX(0){};
	std::string operator[](unsigned int index);

	//设置开始列
	void setPos(unsigned int pos){_posX = pos;};
	unsigned int getPos(){return _posX;};
	unsigned int count()const;
private:
	unsigned int _posX;
	std::map<unsigned int,std::string> _data;
};



CSV.CPP


//mfc程序需要加预定义头
//#include "stdafx.h"
#include "CSV.h"
#include <sstream>
#include <fstream>
using namespace std;


CCSV::CCSV(std::string fileName)
	:_fileName(fileName)
	,_posX(0)
	,_posY(0)
{

}

bool CCSV::parse( unsigned int lineMax /*= ~0*/ )
{
	_data.clear();
	_lastErrol.clear();
	if(_fileName.empty())
	{
		_lastErrol = "File name is empty";
		return false;
	}

	ifstream ifs(_fileName,ios::in);
	if(!ifs.good()) 
	{
		_lastErrol = "Can't open file";
		return false;
	}
	string line;
	string member;
	getline(ifs,line);	
	for (unsigned int i = 0;i<lineMax && !ifs.eof();++i)
	{
		line.push_back(',');		
		CSVRow row;

		int icolonCount = 0,icolumn = 0;
		int ibegin = -1,iend = 0;
		for (auto j = 0;j < line.length();j++)
		{
			char c = line[j];
			switch(c)
			{
			case '"':
				//在开始或者逗号前,在结束或者逗号后,则记录转义符
				if((icolonCount ==0 &&(j == 0 || line[j-1] == ','))
					||(icolonCount == 1 &&(j == line.length()-1 || line[j+1] == ',')))
				{
					icolonCount++;
				}
				break;
			case ',':
				if(icolonCount%2 == 0)
				{
					iend = j;
					//当为双数时,表示退出了双引号范围
					if(iend-ibegin>1)
					{
						//存在过'"'转意符,则删除前后引号
						int ib = ibegin+1+(icolonCount>0?1:0);
						int len = iend-(icolonCount>0?1:0)-ib;
						string str = line.substr(ib,len);

						//删除双引号转意
						if(icolonCount>0)
						{
							unsigned int pos = 0;
							pos = str.find("\"\"",pos);

							while (pos != string::npos)
							{							
								str.erase(str.begin()+pos);
								pos+=2;
								pos = str.find("\"\"",pos);
							}
						}
						row._data[icolumn] = str;
					}
					icolumn++;
					icolonCount = 0;
					ibegin = j;
				}				
				break;
			}
		}

		_data[i] = move(row);
		getline(ifs,line);		
	}
	return true;
}

CSVRow CCSV::operator[]( unsigned int index )
{
	if(!_data.empty())
	{
		auto pos = _data.find(index+_posY);
		if(pos != _data.end())
		{
			pos->second.setPos(_posX);
			return pos->second;
		}
	}	
	return CSVRow();
}

void CCSV::MoveTo( unsigned int x, unsigned int y )
{
	_posX = x;
	_posY = y;
}

unsigned int CCSV::count() const
{
	auto count = _data.size()-_posY;
	return count<0?0:count;
}

std::string CSVRow::operator[]( unsigned int index )
{
	if(!_data.empty())
	{
		auto pos = _data.find(index+_posX);
		if(pos != _data.end())
		{
			return pos->second;
		}
	}	
	return "";
}

unsigned int CSVRow::count() const
{
	return !_data.empty()?_data.rbegin()->first:0;
}




相关阅读