看到网上很多,都有解析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;
}