//---------------------------------------------------------------------------- // EgalTech 2013-2014 //---------------------------------------------------------------------------- // File : StringUtils.cpp Data : 13.01.15 Versione : 1.6a2 // Contenuto : Implementazione delle funzioni di utilità per le stringhe. // // // // Modifiche : 20.01.13 DS Creazione modulo. // 02.12.13 DS Agg. FromString per Vector3d, Point3d e Point3d+W. // 19.01.14 DS Tokenize con Atom ora funziona su più livelli. // 17.03.14 DS Agg. CurrDateTime. // 13.01.15 DS Agg. CurrDateTime. // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "DllMain.h" #include "/EgtDev/Include/EGnStringUtils.h" #include "/EgtDev/Include/EgtILogger.h" #include using namespace std ; //---------------------------------------------------------------------------- static inline void SkipSpaces( const char*& pC) { while ( *pC == ' ' || *pC == '\t') ++ pC ; } //---------------------------------------------------------------------------- bool FromString( const string& sVal, INTVECTOR& vnVal) { // pulisco il vettore dei risultati vnVal.clear() ; // se stringa vuota, esco con successo (per compatibilità con versione precedente) if ( IsEmptyOrSpaces( sVal)) return true ; // ciclo sulla stringa const char* pFirst = sVal.data() ; while ( true) { int nVal ; auto answer = fast_float::from_chars_advanced( pFirst, sVal.data() + sVal.size(), nVal, FAST_FLOAT_OPTS) ; if ( answer.ec != std::errc()) return false ; vnVal.push_back( nVal) ; const char* pLast = answer.ptr ; SkipSpaces( pLast) ; if ( pLast[0] == '\0') return true ; if ( pLast[0] != ',') return false ; pFirst = pLast + 1 ; SkipSpaces( pFirst) ; if ( pFirst[0] == '\0') return true ; } // posizione non raggiungibile (return inutile) } //---------------------------------------------------------------------------- bool FromString( const string& sVal, DBLVECTOR& vdVal) { // pulisco il vettore dei risultati vdVal.clear() ; // se stringa vuota, esco con successo (per compatibilità con versione precedente) if ( IsEmptyOrSpaces( sVal)) return true ; // ciclo sulla stringa const char* pFirst = sVal.data() ; while ( true) { double dVal ; auto answer = fast_float::from_chars( pFirst, sVal.data() + sVal.size(), dVal, FAST_FLOAT_FMT) ; if ( answer.ec != std::errc()) return false ; vdVal.push_back( dVal) ; const char* pLast = answer.ptr ; SkipSpaces( pLast) ; if ( pLast[0] == '\0') return true ; if ( pLast[0] != ',') return false ; pFirst = pLast + 1 ; SkipSpaces( pFirst) ; if ( pFirst[0] == '\0') return true ; } // posizione non raggiungibile (return inutile) } //---------------------------------------------------------------------------- bool FromString( const string& sVal, STRVECTOR& vsVal) { return Tokenize( sVal, ",", vsVal) ; } //---------------------------------------------------------------------------- const string ToString( double dVal, int nPrec, int* pnErr) { const double BIG_NUMBER = 1e10 ; const int MAX_PREC = 12 ; // verifiche (precisione e grande numero) bool bCutTrailingZero = ( nPrec > 0) ; nPrec = min( abs( nPrec), MAX_PREC) ; bool bStdNbr = ( abs( dVal) < BIG_NUMBER) ; // converto in stringa const int nBuffSize = 32 ; char szBuff[nBuffSize]{} ; auto Res = ( bStdNbr ? to_chars( szBuff, szBuff + nBuffSize - 1, dVal, chars_format::fixed, nPrec) : to_chars( szBuff, szBuff + nBuffSize - 1, dVal, chars_format::scientific)) ; if ( Res.ec != std::errc()) { string sOut = make_error_code( Res.ec).message() ; LOG_ERROR( GetEGnLogger(), sOut.c_str()) if ( pnErr != nullptr) *pnErr = int( Res.ec) ; return "#Error" ; } // se abilitato e inserito un punto decimale tolgo i trailing zero if ( bCutTrailingZero && bStdNbr) { char* pDest = Res.ptr ; pDest -- ; while ( *pDest == '0') { *pDest = '\0' ; pDest -- ; } if ( *pDest == '.') *pDest = '\0' ; } if ( pnErr != nullptr) *pnErr = 0 ; if ( szBuff[0] == '-' && szBuff[1] == '0' && szBuff[2] == '\0') return "0" ; else return szBuff ; } //---------------------------------------------------------------------------- const string ToString( const INTVECTOR& vnVal, int nPrec) { // se vettore vuoto, stringa vuota if ( vnVal.empty()) return "" ; // costruisco la stringa string sDest ; sDest.reserve( 8 * vnVal.size()) ; for ( size_t i = 0 ; i < vnVal.size() ; ++ i) sDest += ToString( vnVal[i], nPrec) + "," ; sDest.pop_back() ; return sDest ; } //---------------------------------------------------------------------------- const string ToString( const DBLVECTOR& vdVal, int nPrec) { // se vettore vuoto, stringa vuota if ( vdVal.empty()) return "" ; // costruisco la stringa string sDest ; sDest.reserve( 14 * vdVal.size()) ; for ( size_t i = 0 ; i < vdVal.size() ; ++ i) sDest += ToString( vdVal[i], nPrec) + "," ; sDest.pop_back() ; return sDest ; } //---------------------------------------------------------------------------- const string ToString( const STRVECTOR& vsVal) { // se vettore vuoto, stringa vuota if ( vsVal.empty()) return "" ; // costruisco la stringa int nLen = 0 ; for ( size_t i = 0 ; i < vsVal.size() ; ++ i) nLen += int( vsVal[i].length()) + 1 ; string sDest ; sDest.reserve( nLen) ; for ( size_t i = 0 ; i < vsVal.size() ; ++ i) sDest += vsVal[i] + "," ; sDest.pop_back() ; return sDest ; } //---------------------------------------------------------------------------- void Split( const string& sString, const string& sSeparator, bool bFirstVsLast, string& sFirst, string& sLast) { // verifico definizione separatore if ( sSeparator.empty()) { sFirst.clear() ; sLast.clear() ; return ; } // cerco il separatore string::size_type iPos = ( bFirstVsLast ? sString.find( sSeparator) : sString.rfind( sSeparator)) ; // se trovato if ( iPos != string::npos) { if ( iPos > 0) sFirst = sString.substr( 0, iPos) ; else sFirst.clear() ; if ( ( iPos + 1) < sString.length()) sLast = sString.substr( iPos + 1) ; else sLast.clear() ; } // altrimenti else { sFirst = sString ; sLast.clear() ; } } //---------------------------------------------------------------------------- bool Tokenize( const string& sString, const string& sSeparators, STRVECTOR& vsTokens) { // pulisco il risultato vsTokens.clear() ; // parto dall'inizio string::size_type iPosStart = ( sString.empty() ? string::npos : 0) ; // mentre esiste un nuovo inizio di token while ( iPosStart != string::npos) { // cerco il primo separatore string::size_type iPosEnd = sString.find_first_of( sSeparators, iPosStart) ; // se arrivato alla fine, aggiungo il token al vettore if ( iPosEnd == string::npos) vsTokens.push_back( sString.substr( iPosStart)) ; // altrimenti aggiungo se separatore diverso da spazio o risultato non vuoto else if ( sString[iPosEnd] != ' ' || iPosEnd > iPosStart) vsTokens.push_back( sString.substr( iPosStart, iPosEnd - iPosStart)) ; // cerco l'inizio di un nuovo token iPosStart = ( iPosEnd != string::npos ? iPosEnd + 1 : string::npos) ; } return true ; } //---------------------------------------------------------------------------- bool TokenizePlus( const string& sString, const string& sHeaders, STRVECTOR& vsTokens) { // pulisco il risultato vsTokens.clear() ; // parto dall'inizio string::size_type iPosStart = ( sString.empty() ? string::npos : 0) ; // mentre esiste un nuovo inizio di token while ( iPosStart != string::npos) { // cerco il successivo carattere di intestazione string::size_type iPosEnd = sString.find_first_of( sHeaders, iPosStart + 1) ; // aggiungo il token al vettore vsTokens.push_back( sString.substr( iPosStart, iPosEnd - iPosStart)) ; // cerco l'inizio di un nuovo token iPosStart = iPosEnd ; } return true ; } //---------------------------------------------------------------------------- bool Tokenize( const string& sString, const string& sSeparators, const string& sAtomStarts, const string& sAtomEnds, STRVECTOR& vsTokens) { // i separatori devono essere diversi da inizio e fine di atomi if ( sAtomStarts.find_first_of( sSeparators) != string::npos || sAtomEnds.find_first_of( sSeparators) != string::npos) return false ; // pulisco il risultato vsTokens.clear() ; // se la stringa è vuota non c'è niente da cercare if ( sString.empty()) return true ; // parto dall'inizio int nOpenAtom = 0 ; string::size_type iPosStart = 0 ; string::size_type iPosEnd = iPosStart ; // mentre esiste un nuovo carattere while ( iPosEnd < sString.size()) { // trovo separatore non all'interno di un atomo if ( sSeparators.find( sString[iPosEnd]) != string::npos && nOpenAtom <= 0) { // aggiungo il token al vettore vsTokens.push_back( sString.substr( iPosStart, iPosEnd - iPosStart)) ; // passo al carattere successivo ++ iPosEnd ; // imposto nuovo inizio di token iPosStart = ( iPosEnd < sString.size() ? iPosEnd : string::npos) ; } // trovo inizio di atomo else if ( sAtomStarts.find( sString[iPosEnd]) != string::npos) { ++ nOpenAtom ; // passo al carattere successivo ++ iPosEnd ; } // trovo fine di atomo else if ( sAtomEnds.find( sString[iPosEnd]) != string::npos) { -- nOpenAtom ; // passo al carattere successivo ++ iPosEnd ; } // carattere normale, vado oltre else ++ iPosEnd ; } // se è rimasto un ultimo token if ( iPosStart != string::npos) vsTokens.push_back( sString.substr( iPosStart)) ; return true ; } //---------------------------------------------------------------------------- int ReplaceString( string& sString, const string& sOld, const string& sNew) { int nSubs = 0 ; size_t pos = 0 ; while ( ( pos = sString.find( sOld, pos)) != string::npos) { sString.replace( pos, sOld.length(), sNew) ; pos += sNew.length() ; nSubs ++ ; } return nSubs ; } //---------------------------------------------------------------------------- const string CurrDateTime( void) { // seconds elapsed since midnight, January 1, 1970 time_t _time ; time( &_time) ; // structured time tm _tm ; if ( localtime_s( &_tm, &_time) != 0) return "time/date error" ; // string format const int DT_LEN = 24 ; char szDateTime[DT_LEN] = { '\0'} ; strftime( szDateTime, DT_LEN, "%Y/%m/%d %H:%M:%S", &_tm) ; string sDateTime = szDateTime ; return sDateTime ; }