8ce22a9b4c
- le funzioni ToStringAdv spostate negli include in cui erano dichiarate.
358 lines
12 KiB
C++
358 lines
12 KiB
C++
//----------------------------------------------------------------------------
|
|
// 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 <time.h>
|
|
|
|
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 ;
|
|
}
|