//---------------------------------------------------------------------------- // EgalTech 2013-2025 //---------------------------------------------------------------------------- // File : EGnStringUtils.h Data : 18.09.25 Versione : 2.7i1 // Contenuto : Dichiarazione delle funzioni di utilità per le stringhe. // // // // Modifiche : 20.11.13 DS Creazione modulo. // 20.10.15 DS Agg. FromString e ToString per std::array. // 18.09.25 DS Agg. FromString e ToString per long long. // //---------------------------------------------------------------------------- #pragma once #include "/EgtDev/Include/EgtStringBase.h" #include "/EgtDev/Include/EgtNumCollection.h" #include "/EgtDev/Extern/fast_float/fast_float.h" #include #include #include //----------------------- Macro per import/export ----------------------------- #undef EGN_EXPORT #if defined( I_AM_EGN) // da definirsi solo nella DLL #define EGN_EXPORT __declspec( dllexport) #else #define EGN_EXPORT __declspec( dllimport) #endif //---------------------------------------------------------------------------- inline std::string& TrimLeft( std::string& sString, const char* szTarget = " \t\r\n") { size_t iStartPos = sString.find_first_not_of( szTarget) ; if ( iStartPos != std::string::npos) sString.erase( 0, iStartPos) ; else sString.clear() ; return sString ; } inline std::string& TrimRight( std::string& sString, const char* szTarget = " \t\r\n") { size_t iEndPos = sString.find_last_not_of( szTarget) ; if ( iEndPos != std::string::npos) sString.erase( iEndPos + 1) ; else sString.clear() ; return sString ; } inline std::string& Trim( std::string& sString, const char* szTarget = " \t\r\n") { return TrimLeft( TrimRight( sString, szTarget), szTarget) ; } inline std::string& TrimUtf8Bom( std::string& sString) { if ( sString[0] == '\xef' && sString[1] == '\xbb' && sString[2] == '\xbf') sString.erase( 0, 3) ; return sString ; } //---------------------------------------------------------------------------- inline std::string& ToUpper( std::string& sString) { std::transform( sString.begin(), sString.end(), sString.begin(), ::toupper) ; return sString ; } inline std::string& ToLower( std::string& sString) { std::transform( sString.begin(), sString.end(), sString.begin(), ::tolower) ; return sString ; } inline bool EqualNoCase( const std::string& sL, const std::string& sR) { return ( sL.size() == sR.size() && std::equal( sL.cbegin(), sL.cend(), sR.cbegin(), []( std::string::value_type cL, std::string::value_type cR) { return tolower( cL) == tolower( cR); })) ; } //---------------------------------------------------------------------------- inline bool IsEmptyOrSpaces( const std::string& sName) { return ( &sName == nullptr || sName.empty() || sName.find_first_not_of( " \t\r\n") == std::string::npos) ; } //---------------------------------------------------------------------------- inline bool IsNullOrSpace( char cChar) { return ( cChar == '\0' || cChar == ' ' || cChar == '\t' || cChar == '\r' || cChar == '\n') ; } //---------------------------------------------------------------------------- inline bool IsValidFileName( const std::string& sName) { if ( &sName == nullptr || sName.empty()) return false ; return ( sName.find_first_of( "<>/\\\":?*|", 0) == std::string::npos) ; } //---------------------------------------------------------------------------- inline bool ValidateFileName( std::string& sName) { std::string::size_type i ; while ( ( i = sName.find_first_of( "<>/\\\":?*|")) != std::string::npos) sName[i] = '_' ; return true ; } //---------------------------------------------------------------------------- inline bool IsValidDxfName( const std::string& sName, bool bAdvanced) { if ( &sName == nullptr || sName.empty()) return false ; std::string sOut = "<>/\\\":;?*|='" ; if ( ! bAdvanced) sOut += " ." ; return ( sName.find_first_of( sOut, 0) == std::string::npos) ; } //---------------------------------------------------------------------------- inline bool ValidateDxfName( std::string& sName, bool bAdvanced) { std::string sOut = "<>/\\\":;?*|='" ; if ( ! bAdvanced) sOut += " ." ; std::string::size_type i ; while ( ( i = sName.find_first_of( sOut)) != std::string::npos) sName[i] = '_' ; return true ; } //---------------------------------------------------------------------------- #define FAST_FLOAT_FMT fast_float::chars_format::general | fast_float::chars_format::allow_leading_plus | fast_float::chars_format::skip_white_space #define FAST_FLOAT_OPTS fast_float::parse_options( FAST_FLOAT_FMT) inline bool FromString( const std::string& sVal, int& nVal) { auto answer = fast_float::from_chars_advanced( sVal.data(), sVal.data() + sVal.size(), nVal, FAST_FLOAT_OPTS) ; return ( answer.ec == std::errc() && answer.ptr != sVal.data()) ; } inline bool FromString( const std::string& sVal, unsigned int& nVal) { auto answer = fast_float::from_chars_advanced( sVal.data(), sVal.data() + sVal.size(), nVal, FAST_FLOAT_OPTS) ; return ( answer.ec == std::errc() && answer.ptr != sVal.data()) ; } inline bool FromString( const std::string& sVal, long long& nVal) { auto answer = fast_float::from_chars_advanced( sVal.data(), sVal.data() + sVal.size(), nVal, FAST_FLOAT_OPTS) ; return ( answer.ec == std::errc() && answer.ptr != sVal.data()) ; } inline bool FromString( const std::string& sVal, bool& bVal) { int nTmp ; if ( ! FromString( sVal, nTmp)) return false ; bVal = ( nTmp != 0) ; return true ; } inline bool FromString( const std::string& sVal, double& dVal) { auto answer = fast_float::from_chars( sVal.data(), sVal.data() + sVal.size(), dVal, FAST_FLOAT_FMT) ; return ( answer.ec == std::errc() && answer.ptr != sVal.data()) ; } template bool FromString( const std::string& sVal, int (&nVal)[size]) { const char* pFirst = sVal.data() ; for ( int i = 0 ; i < size ; ++ i) { auto answer = fast_float::from_chars_advanced( pFirst, sVal.data() + sVal.size(), nVal[i], FAST_FLOAT_OPTS) ; if ( answer.ec != std::errc() || ( i < size - 1 && answer.ptr[0] != ',')) return false ; pFirst = answer.ptr + 1 ; } return true ; } template bool FromString( const std::string& sVal, double (&dVal)[size]) { const char* pFirst = sVal.data() ; for ( int i = 0 ; i < size ; ++ i) { auto answer = fast_float::from_chars( pFirst, sVal.data() + sVal.size(), dVal[i], FAST_FLOAT_FMT) ; if ( answer.ec != std::errc() || ( i < size - 1 && answer.ptr[0] != ',')) return false ; pFirst = answer.ptr + 1 ; } return true ; } template bool FromString( const std::string& sVal, std::array& dVal) { const char* pFirst = sVal.data() ; for ( int i = 0 ; i < size ; ++ i) { auto answer = fast_float::from_chars( pFirst, sVal.data() + sVal.size(), dVal[i], FAST_FLOAT_FMT) ; if ( answer.ec != std::errc() || ( i < size - 1 && answer.ptr[0] != ',')) return false ; pFirst = answer.ptr + 1 ; } return true ; } EGN_EXPORT bool FromString( const std::string& sVal, INTVECTOR& vnVal) ; EGN_EXPORT bool FromString( const std::string& sVal, DBLVECTOR& vdVal) ; EGN_EXPORT bool FromString( const std::string& sVal, STRVECTOR& vsVal) ; //---------------------------------------------------------------------------- inline const std::string ToStringAdv( int nVal, int nPrec = 1, int nRadix = 10, int* pnErr = nullptr) { // eseguo conversione const int nBuffSize = 36 ; char szBuff[nBuffSize]{} ; auto Res = std::to_chars( szBuff, szBuff + nBuffSize - 1, nVal, nRadix) ; if ( Res.ec != std::errc()) { if ( pnErr != nullptr) *pnErr = int( Res.ec) ; return "#Error" ; } // gestione codice di errore if ( pnErr != nullptr) *pnErr = 0 ; // verifico lunghezza minima int nLen = (int) strlen( szBuff) ; if ( nLen >= nPrec) return szBuff ; // porto la stringa alla minima lunghezza std::string sBuff( szBuff) ; sBuff.insert( 0, ( nPrec - nLen), '0') ; return sBuff ; } inline const std::string ToString( int nVal, int nPrec = 1, int nRadix = 10, int* pnErr = nullptr) { // se necessario processing avanzato if ( nPrec > 1 || nRadix < 6) return ToStringAdv( nVal, nPrec, nRadix, pnErr) ; // eseguo conversione const int nBuffSize = 16 ; char szBuff[nBuffSize]{} ; auto Res = std::to_chars( szBuff, szBuff + nBuffSize - 1, nVal, nRadix) ; if ( Res.ec != std::errc()) { if ( pnErr != nullptr) *pnErr = int( Res.ec) ; return "#Error" ; } // gestione codice di errore if ( pnErr != nullptr) *pnErr = 0 ; return szBuff ; } inline const std::string ToStringAdv( unsigned int nVal, int nPrec = 1, int nRadix = 10, int* pnErr = nullptr) { // eseguo conversione const int nBuffSize = 36 ; char szBuff[nBuffSize]{} ; auto Res = std::to_chars( szBuff, szBuff + nBuffSize - 1, nVal, nRadix) ; if ( Res.ec != std::errc()) { if ( pnErr != nullptr) *pnErr = int( Res.ec) ; return "#Error" ; } // gestione codice di errore if ( pnErr != nullptr) *pnErr = 0 ; // verifico lunghezza minima int nLen = (int) strlen( szBuff) ; if ( nLen >= nPrec) return szBuff ; // porto la stringa alla minima lunghezza std::string sBuff( szBuff) ; sBuff.insert( 0, ( nPrec - nLen), '0') ; return sBuff ; } inline const std::string ToString( unsigned int nVal, int nPrec = 1, int nRadix = 10, int* pnErr = nullptr) { // se necessario processing avanzato if ( nPrec > 1 || nRadix < 6) return ToStringAdv( nVal, nPrec, nRadix, pnErr) ; // eseguo conversione const int nBuffSize = 16 ; char szBuff[nBuffSize]{} ; auto Res = std::to_chars( szBuff, szBuff + nBuffSize - 1, nVal, nRadix) ; if ( Res.ec != std::errc()) { if ( pnErr != nullptr) *pnErr = int( Res.ec) ; return "#Error" ; } // gestione codice di errore if ( pnErr != nullptr) *pnErr = 0 ; return szBuff ; } template const std::string ToString( const unsigned int (&nVal)[size], int nPrec = 1) { std::string sDest ; sDest.reserve( 8 * size) ; for ( const auto& nV : nVal) sDest += ToString( nV, nPrec) + "," ; sDest.pop_back() ; return sDest ; } inline const std::string ToStringAdv( long long nVal, int nPrec = 1, int nRadix = 10, int* pnErr = nullptr) { // eseguo conversione const int nBuffSize = 68 ; char szBuff[nBuffSize]{} ; auto Res = std::to_chars( szBuff, szBuff + nBuffSize - 1, nVal, nRadix) ; if ( Res.ec != std::errc()) { if ( pnErr != nullptr) *pnErr = int( Res.ec) ; return "#Error" ; } // gestione codice di errore if ( pnErr != nullptr) *pnErr = 0 ; // verifico lunghezza minima int nLen = (int) strlen( szBuff) ; if ( nLen >= nPrec) return szBuff ; // porto la stringa alla minima lunghezza std::string sBuff( szBuff) ; sBuff.insert( 0, ( nPrec - nLen), '0') ; return sBuff ; } inline const std::string ToString( long long nVal, int nPrec = 1, int nRadix = 10, int* pnErr = nullptr) { // se necessario processing avanzato if ( nPrec > 1 || nRadix < 6) return ToStringAdv( nVal, nPrec, nRadix, pnErr) ; // eseguo conversione const int nBuffSize = 16 ; char szBuff[nBuffSize]{} ; auto Res = std::to_chars( szBuff, szBuff + nBuffSize - 1, nVal, nRadix) ; if ( Res.ec != std::errc()) { if ( pnErr != nullptr) *pnErr = int( Res.ec) ; return "#Error" ; } // gestione codice di errore if ( pnErr != nullptr) *pnErr = 0 ; return szBuff ; } template const std::string ToString( const int (&nVal)[size], int nPrec = 1) { std::string sDest ; sDest.reserve( 8 * size) ; for ( const auto& nV : nVal) sDest += ToString( nV, nPrec) + "," ; sDest.pop_back() ; return sDest ; } inline const std::string ToString( bool bVal) { return std::string( ( bVal ? "1" : "0")) ; } EGN_EXPORT const std::string ToString( double dVal, int nPrec = 6, int* pnErr = nullptr) ; template const std::string ToString( const double (&dVal)[size], int nPrec = 6) { std::string sDest ; sDest.reserve( 14 * size) ; for ( const auto& dV : dVal) sDest += ToString( dV, nPrec) + "," ; sDest.pop_back() ; return sDest ; } template const std::string ToString( const std::array& dVal, int nPrec = 6) { std::string sDest ; sDest.reserve( 14 * size) ; for ( const auto& dV : dVal) sDest += ToString( dV, nPrec) + "," ; sDest.pop_back() ; return sDest ; } EGN_EXPORT const std::string ToString( const INTVECTOR& vnVal, int nPrec = 1) ; EGN_EXPORT const std::string ToString( const DBLVECTOR& vdVal, int nPrec = 6) ; EGN_EXPORT const std::string ToString( const STRVECTOR& vsVal) ; //---------------------------------------------------------------------------- EGN_EXPORT void Split( const std::string& sString, const std::string& sSeparator, bool bFirstVsLast, std::string& sFirst, std::string& sLast) ; inline void SplitFirst( const std::string& sString, const std::string& sSeparator, std::string& sFirst, std::string& sLast) { Split( sString, sSeparator, true, sFirst, sLast) ; } inline void SplitLast( const std::string& sString, const std::string& sSeparator, std::string& sFirst, std::string& sLast) { Split( sString, sSeparator, false, sFirst, sLast) ; } //---------------------------------------------------------------------------- EGN_EXPORT bool Tokenize( const std::string& sString, const std::string& sSeparators, STRVECTOR& vsTokens) ; EGN_EXPORT bool TokenizePlus( const std::string& sString, const std::string& sHeaders, STRVECTOR& vsTokens) ; EGN_EXPORT bool Tokenize( const std::string& sString, const std::string& sSeparators, const std::string& sAtomStarts, const std::string& sAtomEnds, STRVECTOR& vsTokens) ; //---------------------------------------------------------------------------- EGN_EXPORT int ReplaceString( std::string& sString, const std::string& sOld, const std::string& sNew) ; //---------------------------------------------------------------------------- EGN_EXPORT const std::string CurrDateTime( void) ;