00001
00002
00003 #ifdef English_dox
00004
00005
00006
00007
00008
00009 #endif
00010
00011 #ifdef Spanish_dox
00012
00013
00014
00015
00016
00017 #endif
00018
00019 #include "CSV.h"
00020
00021 #define COMMA ','
00022 #define DQUOTE '"'
00023 #define LF '\n' // Line Feed
00024 #define CR '\r' // Carriage Return
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 #ifdef English_dox
00054
00055
00056
00057
00058
00059
00060
00061
00062 #endif
00063 #ifdef Spanish_dox
00064
00065
00066
00067
00068
00069
00070
00071
00072 #endif
00073 bool automataCSV( std::string& csv, std::istream& CIN ) {
00074 csv.clear();
00075 if ( CIN.fail() || CIN.eof() ) {
00076 return false;
00077 }
00078 int state=0; char ch;
00079 bool trailing_CR = false;
00080 bool ret_val = true;
00081 for (;;) {
00082 CIN.get(ch);
00083 if ( CIN.fail() || CIN.eof() ) {
00084 return ret_val;
00085 }
00086 csv += ch;
00087
00088 switch (state) {
00089 case 0: {
00090 if ( ch == COMMA ) {
00091 return ret_val;
00092 }
00093 else if ( ch == LF ) {
00094 return ret_val;
00095 }
00096 else if ( ch == CR ) {
00097 trailing_CR = true;
00098 state = 3;
00099 }
00100 else if ( ch == DQUOTE ) {
00101 state = 1;
00102 }
00103 else {
00104 state = 3;
00105 }
00106 }
00107 break;
00108
00109 case 1: {
00110 if ( ch == DQUOTE ) {
00111 state = 2;
00112 }
00113
00114
00115
00116 }
00117 break;
00118
00119 case 2: {
00120 if ( ch == COMMA ) {
00121
00122 return ret_val;
00123 } else if ( ch == LF ) {
00124
00125 return ret_val;
00126 }
00127 else if ( trailing_CR ) {
00128 trailing_CR = false;
00129 ret_val = false;
00130 state = 3;
00131 }
00132 else if ( ch == CR ) {
00133 trailing_CR = true;
00134
00135 }
00136 else if ( ch == DQUOTE ) {
00137 state = 1;
00138 }
00139 else {
00140 ret_val = false;
00141 state = 3;
00142 }
00143 }
00144 break;
00145
00146 case 3: {
00147 if ( ch == COMMA ) {
00148
00149 return ret_val;
00150 }
00151 else if ( ch == LF ) {
00152
00153 return ret_val;
00154 }
00155 else {
00156
00157
00158 }
00159 }
00160 break;
00161
00162 }
00163 }
00164
00165 return ret_val;
00166 }
00167
00168 void singleDQUOTE( std::string & str );
00169
00170 bool getNextCSV( std::string& csv, std::istream& CIN ) {
00171 bool correct = automataCSV( csv, CIN );
00172 bool ret_val = false;
00173 size_t N = csv.length();
00174
00175 if ( correct ) {
00176 if ( csv.empty() ) {
00177 return ret_val;
00178 }
00179 N--;
00180 if ( csv[N] == COMMA ) {
00181 csv.erase(N);
00182 }
00183 else if( csv[N] == LF ) {
00184 ret_val = true;
00185 csv.erase(N);
00186 if ( N>0 ) {
00187 N--;
00188 if( csv[N] == CR ) {
00189 csv.erase(N);
00190 }
00191 }
00192 }
00193
00194 if ( ! csv.empty() ) {
00195 if ( csv[0] == DQUOTE ) {
00196 singleDQUOTE( csv );
00197 }
00198 }
00199 }
00200
00201 else {
00202 if ( N>0 ) {
00203 N--;
00204 if ( csv[N] == COMMA ) {
00205 csv.erase(N,1);
00206 }
00207 }
00208 }
00209 return ret_val;
00210 }
00211
00212 void setQuotedCSV( std::string& res , const std::string& value ) {
00213 std::string::const_iterator ch;
00214 bool quote_surround = false;
00215 res.clear();
00216 for ( ch = value.begin(); ch != value.end(); ++ch ) {
00217 if ( isspace( *ch ) || *ch == COMMA ) {
00218 quote_surround = true;
00219 }
00220 else if ( *ch == DQUOTE ) {
00221 res += DQUOTE;
00222 quote_surround = true;
00223 }
00224 res += *ch;
00225 }
00226
00227 if ( quote_surround ) {
00228 res = DQUOTE + res + DQUOTE;
00229 }
00230 }
00231
00232 void trim( std::string & str ) {
00233 if ( str.empty() ) {
00234 return;
00235 }
00236
00237
00238 std::string::size_type i = 0, LEN = str.length();
00239 while ( i < LEN ) {
00240 if ( isspace(str[i]) ) {
00241 ++i;
00242 }
00243 else {
00244 break;
00245 }
00246 }
00247
00248 std::string::size_type j = LEN;
00249 while ( j > 0 ) {
00250 --j;
00251 if ( ! isspace(str[j]) ) {
00252 break;
00253 }
00254 }
00255
00256 str = str.substr(i,j-i+1);
00257 }
00258
00259 void trimCSV( std::string & str ) {
00260 trim( str );
00261 if ( str.empty() ) {
00262 return;
00263 }
00264
00265
00266 std::string::size_type N = str.length()-1;
00267 if ( str[0] != DQUOTE || str[N] != DQUOTE ) {
00268 return;
00269 }
00270
00271
00272 singleDQUOTE( str );
00273 return;
00274 }
00275
00276
00277 #ifdef English_dox
00278
00279 #endif
00280 #ifdef Spanish_dox
00281
00282 #endif
00283 void singleDQUOTE( std::string & str ) {
00284
00285 std::string tmp;
00286 std::string::const_iterator from, next;
00287 for ( from = str.begin(); from != str.end(); ++from ) {
00288 tmp.push_back( *from );
00289 if ( *from == DQUOTE ) {
00290 next = from; next++;
00291 if ( next == str.end() ) {
00292 break;
00293 }
00294 else if ( *next == DQUOTE ) {
00295 from = next;
00296 }
00297 }
00298 }
00299
00300 str = tmp.substr(1, tmp.length()-2);
00301 return;
00302 }
00303
00304 void chop( std::string & str , char ch ) {
00305 if ( str.empty() ) {
00306 return;
00307 }
00308 std::string::size_type N = str.length()-1;
00309 if ( str[N] == ch ) {
00310 str.erase(N);
00311 }
00312 }
00313
00314
00315 #if 0
00316
00317
00318 void test_CSV::test_rebuildDquote() {
00319 void rebuildDquote( std::string & str );
00320 {{
00321 std::string s;
00322 s = "\"" ; rebuildDquote(s);
00323 assertTrue( s == "\"\"");
00324 s = "\" \" \"" ; rebuildDquote(s);
00325 assertTrue( s == "\"\" \"\" \"\"");
00326 s = "3,4\"" ; rebuildDquote(s);
00327 assertTrue( s == "3,4\"\"");
00328 s = " ," ; rebuildDquote(s);
00329 assertTrue( s == " ,");
00330 }}
00331 {
00332 std::string s = "\"2\",3, \r\n";
00333 rebuildDquote(s);
00334 assertTrue( s == "\"\"2\"\",3, \r\n");
00335 }
00336 }
00337
00338 #ifdef English_dox
00339
00340
00341
00342
00343
00344
00345
00346
00347 #endif
00348 #ifdef Spanish_dox
00349
00350
00351
00352
00353
00354
00355
00356
00357 #endif
00358 void rebuildDquote( std::string & str ) {
00359 std::string res;
00360 std::string::const_iterator ch;
00361 for ( ch = str.begin(); ch != str.end(); ++ch ) {
00362 res += *ch;
00363 if ( *ch == DQUOTE ) {
00364 res += DQUOTE;
00365 }
00366 }
00367 str = res;
00368 }
00369
00370 bool getNextCSV_OLD( std::string& csv, std::istream& CIN ) {
00371 csv.clear();
00372 if ( CIN.fail() ) {
00373 return false;
00374 }
00375 int state=0; char ch;
00376 bool trailing_CR = false;
00377 for (;;) {
00378 CIN.get(ch);
00379 if ( CIN.fail() ) {
00380 return false;
00381 }
00382
00383 switch (state) {
00384 case 0: {
00385 if ( ch == COMMA ) {
00386
00387 return false;
00388 }
00389 else if ( ch == LF ) {
00390
00391 return true;
00392 }
00393 else if ( ch == CR ) {
00394 trailing_CR = true;
00395 csv += CR;
00396 state = 3;
00397 }
00398 else if ( ch == DQUOTE ) {
00399 state = 1;
00400 }
00401 else {
00402 csv += ch;
00403 state = 3;
00404 }
00405 }
00406 break;
00407
00408 case 1: {
00409 if ( ch == DQUOTE ) {
00410 state = 2;
00411 }
00412 else {
00413 csv += ch;
00414
00415 }
00416 }
00417 break;
00418
00419 case 2: {
00420 if ( ch == COMMA ) {
00421
00422 return false;
00423 } else if ( ch == LF ) {
00424
00425 return true;
00426 }
00427 else if ( trailing_CR ) {
00428 rebuildDquote( csv );
00429 csv = DQUOTE + csv + DQUOTE + CR + ch;
00430 trailing_CR = false;
00431 state = 3;
00432 }
00433 else if ( ch == CR ) {
00434 trailing_CR = true;
00435
00436
00437 }
00438 else if ( ch == DQUOTE ) {
00439 csv += DQUOTE;
00440 state = 1;
00441 }
00442 else {
00443 rebuildDquote( csv );
00444 csv= DQUOTE + csv + DQUOTE + ch;
00445 state = 3;
00446 }
00447 }
00448 break;
00449
00450 case 3: {
00451 if ( ch == COMMA ) {
00452 return false;
00453 } else if ( ch == LF ) {
00454 if ( trailing_CR ) {
00455 csv = csv.substr( 0, csv.length()-1 );
00456 }
00457
00458
00459 return true;
00460 }
00461 else if ( ch == CR ) {
00462 trailing_CR = true;
00463 csv += CR;
00464
00465 }
00466 else {
00467 csv += ch;
00468
00469
00470 }
00471 }
00472 break;
00473
00474 }
00475 }
00476
00477 return false;
00478 }
00479
00480 #endif
00481
00482 #ifdef English_dox
00483
00484 #endif
00485 #ifdef Spanish_dox
00486
00487 #endif
00488 namespace csv { }
00489
00490
00491
00492 using namespace std;
00493 using namespace csv;
00494
00495