#include <string>
#include <fstream>
template<class callbackfun> bool csvread( const char* filename, callbackfun cbf, char delimit=',' )
{
std::ifstream file( filename, std::ios::binary );
if( !file ) return false; // 文件打開失敗
bool quo = false; // 此字段是否以雙引號開始
bool quopre = false; // 當此字段以雙引號開始時,前一個是否爲雙引號
std::string val;
size_t row=0, col=0;
for( char c; file.get(c); )
{
if( c == delimit )
{
if( quo && !quopre )
{
val += c;
}
else
{
if( !cbf(row,col,val) )
return false;
quo = false;
quopre = false;
val.clear();
++col;
}
}
else switch( c )
{
case '"':
if( !quo )
{
if( val.empty() )
quo = true;
else
val += c;
}
else if( quopre )
{
quopre = false;
val += c;
}
else
quopre = true;
break;
case '\r':
break;
case '\n':
if( quo )
{
val += c;
}
else
{
if( !cbf(row,col,val) )
return false;
quo = false;
quopre = false;
val.clear();
++row;
col = 0;
}
break;
default:
if( quopre )
{
quo = false;
quopre = false;
}
val += c;
break;
}
}
if( !val.empty() || col!=0 )
{
if( !cbf(row,col,val) )
return false;
}
return file.eof();
}
void csvvalue( const char* str, std::string& val )
{
if( str[strcspn(str,",\"\n")] == '\0' )
{
val.clear();
return;
}
// 如果有 逗號 分號 換行,則用引號括起來,並把其中原有的引號變爲雙份
val = '"';
const char* p1 = str;
for( const char* p2; (p2=strchr(p1,'"'))!=0; p1=p2+1 )
{
val.append( p1, p2-p1+1 );
val.append( 1, '"' );
}
val.append( p1 );
val.append( 1, '"' );
return;
}
//////////////////// 以下爲測試 ////////////////////
#include <iostream>
#include <locale>
using namespace std;
struct foo
{
foo() : row(0), col(0)
{
}
size_t row, col;
bool operator()( size_t r, size_t c, std::string val )
{
if( r != row )
cout << '\n';
if( c != 0 )
cout << '|';
cout << val;
row=r, col=c;
return true;
}
};
int main()
{
// 否則打開含中文的路徑失敗,但可惜的是MinGW用之無效,又不支持"chs"
std::locale loc = std::locale::global( std::locale(std::locale(),"",std::locale::ctype) );
csvread( "C:\\Documents and Settings\\0846\\桌面\\Book1.csv", foo() );
std::string val;
csvvalue( "\"a\"\"b\"\"", val );
return 0;
}