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