Files
EgtGeneral/StringUtils.cpp
T
Dario Sassi 143b7d46df EgtGeneral 1.8b1 :
- modificata Tokenize, ora non salta campi vuoti tra separatori.
2017-02-06 07:46:53 +00:00

412 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 "/EgtDEv/Include/EGnStringUtils.h"
#include <time.h>
using namespace std ;
//----------------------------------------------------------------------------
static inline void
SkipSpaces( const char*& pC)
{
while ( *pC == ' ' || *pC == '\t')
++ pC ;
}
//----------------------------------------------------------------------------
static inline void
SkipSpaces( char*& pC)
{
while ( *pC == ' ' || *pC == '\t')
++ pC ;
}
//----------------------------------------------------------------------------
bool
FromString( const string& sVal, INTVECTOR& vnVal)
{
// pulisco il vettore dei risultati
vnVal.clear() ;
// reset errori di conversione
errno = 0 ;
// ciclo sui caratteri della stringa
const char* pStart = sVal.c_str() ;
SkipSpaces( pStart) ;
while ( ( *pStart >= '0' && *pStart <= '9') || *pStart == '+' || *pStart == '-') {
char* pStop ;
int nVal = strtol( pStart, &pStop, 10) ;
vnVal.push_back( nVal) ;
SkipSpaces( pStop) ;
if ( *pStop == '\0' && errno == 0)
return true ;
if ( *pStop != ',' || errno != 0)
return false ;
pStart = pStop + 1 ;
SkipSpaces( pStart) ;
}
return ( *pStart == '\0' && errno == 0) ;
}
//----------------------------------------------------------------------------
bool
FromString( const string& sVal, DBLVECTOR& vdVal)
{
// pulisco il vettore dei risultati
vdVal.clear() ;
// reset errori di conversione
errno = 0 ;
// ciclo sui caratteri della stringa
const char* pStart = sVal.c_str() ;
SkipSpaces( pStart) ;
while ( ( *pStart >= '0' && *pStart <= '9') ||
*pStart == '+' || *pStart == '-' || *pStart == '.') {
char* pStop ;
double dVal = strtod( pStart, &pStop) ;
vdVal.push_back( dVal) ;
SkipSpaces( pStop) ;
if ( *pStop == '\0' && errno == 0)
return true ;
if ( *pStop != ',' || errno != 0)
return false ;
pStart = pStop + 1 ;
SkipSpaces( pStart) ;
}
return ( *pStart == '\0' && errno == 0) ;
}
//----------------------------------------------------------------------------
bool
FromString( const std::string& sVal, STRVECTOR& vsVal)
{
return Tokenize( sVal, ",", vsVal) ;
}
//----------------------------------------------------------------------------
const string
ToString( double dVal, int nPrec)
{
const double BIG_NUMBER = 1e10 ;
const int BIG_DIGITNBR = 10 ;
const int MAX_PREC = 12 ;
// verifico la precisione
bool bCutTrailingZero = ( nPrec >= 0) ;
nPrec = min( abs( nPrec), MAX_PREC) ;
// converto la mantissa
char szBuff[24] ;
int nErr, nDecimal, nSign ;
if ( fabs( dVal) < BIG_NUMBER)
nErr = _fcvt_s( szBuff, dVal, nPrec, &nDecimal, &nSign) ;
else
nErr = _ecvt_s( szBuff, dVal, BIG_DIGITNBR + nPrec, &nDecimal, &nSign) ;
// se errore, ritorno stringa opportuna
if ( nErr != 0) {
_ASSERT( 0) ;
return "#Error" ;
}
// se buffer vuoto, risultato è numero 0
if ( szBuff[0] == '\0')
return "0" ;
// verifica per forma esponenziale
int nExp ;
if ( nDecimal > BIG_DIGITNBR) {
nExp = nDecimal - 1 ;
nDecimal = 1 ;
}
else
nExp = 0 ;
// puntatori a inizio stringhe
char szDest[32] ;
char* pBuff = szBuff ;
char* pDest = szDest ;
// eventuale inserimento segno '-'
if ( nSign != 0) {
*pDest = '-' ;
pDest ++ ;
} ;
// gestione decimali dopo 0
if ( nDecimal <= 0) {
*pDest = '0' ;
pDest ++ ;
*pDest = '.' ;
pDest ++ ;
for ( ; nDecimal < 0 ; nDecimal ++) {
*pDest = '0' ;
pDest ++ ;
}
nDecimal -- ;
}
// gestione cifre e .
while ( *pBuff != '\0') {
if ( *pBuff == '#') // NAN, INFINITY, INDEFINITE
_ASSERT( 0) ;
if ( nDecimal == 0) {
*pDest = '.' ;
pDest ++ ;
}
nDecimal -- ;
*pDest = *pBuff ;
pDest ++ ;
pBuff ++ ;
}
*pDest = '\0' ;
// se abilitato e inserito un punto decimale tolgo i trailing zero
if ( bCutTrailingZero && nDecimal < 0) {
pDest -- ;
while ( *pDest == '0') {
*pDest = '\0' ;
pDest -- ;
}
if ( *pDest == '.')
*pDest = '\0' ;
else
pDest ++ ;
}
// aggiungo eventuale esponente (sempre compreso tra 9 e 308)
if ( nExp > 0) {
*pDest = 'e' ;
pDest ++ ;
int nTmp = nExp ;
if ( nTmp >= 100) {
*pDest = '0' + ( nTmp / 100) ;
pDest ++ ;
nTmp = nTmp % 100 ;
}
if ( nTmp >= 10 || nExp >= 100) {
*pDest = '0' + ( nTmp / 10) ;
pDest ++ ;
nTmp = nTmp % 10 ;
}
*pDest = '0' + nTmp ;
pDest ++ ;
*pDest = '\0' ;
}
if ( szDest[0] == '-' && szDest[1] == '0' && szDest[2] == '\0')
return "0" ;
else
return szDest ;
}
//----------------------------------------------------------------------------
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)
{
// 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) ;
// aggiungo il token al vettore
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 ;
}