// str2list.h (C) 2011 adolfo@di-mare.com /** \file str2list.h \brief Funciones para crear listas y matrices a partir de hileras. \author Adolfo Di Mare \date 2011 */ #ifndef str2list_h #define str2list_h ///< Evita la inclusión múltiple #include // std::list<> #include // std::string #include // atoi() atol() atof() /** Retorna \c true para todos los caracters considerados como espacios en blanco por \c str2list(). - { , () <> {} [] } && \c isspace(). - El punto \c char('.') no es considerado espacio en blanco ( pues forma parte de un número flotante: \c 1.0e22 ). - false == iswhitespace_str2list( '.' ) . \dontinclude test_str2list.cpp \skipline test::iswhitespace() \until }} \see test_str2list::test_iswhitespace() */ template bool iswhitespace_str2list( CHAR ch ) { if ( ch==',' || isspace(ch) ) { return true; } if ( ch=='(' || ch==')' ) { return true; } if ( ch=='<' || ch=='>' ) { return true; } if ( ch=='{' || ch=='}' ) { return true; } if ( ch=='[' || ch==']' ) { return true; } return false; // NOTA: implementado con plantillas para evitar usar el archivo str2list.cpp } /** Almacena en \c "L<>" la lista de hileras construida en base a \c "str". - En \c "str" están los valores que serán almacenados en \c "L<>" separados por varios delimitadores. - Como delimitadores se usan los caracteres blancos y la coma. - Como delimitadores se usan los caracteres \c ispace() y \c ','. - El punto \c '.' no se interpreta como delimitador. - Los caracteres { , () <> {} [] } son interpretados como blancos y no verifica que estén balanceados o en parejas. - Ignora el paréntesis del principio y del final de \c "str". - Si al principio encuentra el caracter \c '|' procesa la hilera hasta que encuentra el siguiente caracter \c '|'. - No examina lo que está después de la barrita final \c '|'. - Siempre modifica el valor de \c "L<>". - Retorna la última posición de \c "str" que fue examinada. \dontinclude test_str2list.cpp \skipline test::str2list::list() \until }} \see test_str2list::str2list_list() */ template const char* str2list( std::list& L , const char* str ) { L.clear(); if ( str == 0) { return 0; } if (*str == 0) { return str; } while ( iswhitespace_str2list(*str) ) { ++str; } // skip leading blanks if (*str=='|') { ++str; } // skip first '|' std::string val; // next value to store into L const bool IN_WHITESPACE = false; const bool IN_STRING = !IN_WHITESPACE; bool state = IN_WHITESPACE; while ( (*str != 0) && (*str != '|') ) { if ( state == IN_WHITESPACE ) { if ( ! iswhitespace_str2list(*str) ) { state = IN_STRING; val = *str; } } else { // assert( state == IN_STRING ); if ( iswhitespace_str2list(*str) ) { L.push_back( val ); val.clear(); state = IN_WHITESPACE; } else { val += *str; } } ++str; } if ( !val.empty() ) { L.push_back(val); } return str; // NOTA: implementado con plantillas para evitar usar el archivo str2list.cpp } /** Usa \c str2list(L,str) para retornar la lista de valores de \c "str". \dontinclude test_str2list.cpp \skipline test::str2list::example() \until }} \see test_str2list::str2list_example() */ inline std::list str2list( const char* str ) { std::list L; str2list(L,str); return L; } /** Retorna la lista de valores construida en base a \c "str". Usa \c str2list() junto con \c ATON_wrap::ATON(). \tparam N tipo de dato: { int long double } \tparam ATON_wrap Empaque \c ATON() alrededor del convertidor: { atoi() atol() atof() }. */ template std::list str2list_wrap( const char* str ) { std::list L; std::list RES; str2list(L,str); std::list< std::string >::const_iterator it; for ( it= L.begin(); it!=L.end(); ++it ) { RES.push_back( ATON_wrap::ATON(it->c_str()) ); } return RES; } /// Empaque \c ATON() alrededor de la función \c atoi(). struct str2list_int_wrap { /// Retorna \c atoi(str). static int ATON( const char * str ) { return atoi(str); } }; /// Empaque \c ATON() alrededor de la función \c atol(). struct str2list_long_wrap { /// Retorna \c atol(str). static long ATON( const char * str ) { return atol(str); } }; /// Empaque \c ATON() alrededor de la función \c atof(). struct str2list_double_wrap { /// Retorna \c atof(str). static double ATON( const char * str ) { return atof(str); } }; inline std::list intlist( const char* str ) { return str2list_wrap( str ); } ///< Sinónimo de \c makeList_int(). /** Retorna la lista de enteros \c (int) construida en base a \c "str". Usa \c str2list() junto con \c atoi(). \dontinclude test_str2list.cpp \skipline test::intlist() \until }} \see test_str2list::test_intlist() */ inline std::list makeList_int( const char* str ) { return str2list_wrap( str ); } inline std::list longlist( const char* str ) { return str2list_wrap( str ); } ///< Sinónimo de \c makeList_long(). /** Retorna la lista de enteros \c (long) construida en base a \c "str". Usa \c str2list() junto con \c atol(). \dontinclude test_str2list.cpp \skipline test::makeList_long() \until }} \see test_str2list::test_makeList_long() */ inline std::list makeList_long( const char* str ) { return str2list_wrap( str ); } /** Retorna la lista de flotantes construida en base a \c "str". Usa \c str2list() junto con \c atof(). \dontinclude test_str2list.cpp \skipline test::doublelist() \until }} \see test_str2list::test_doublelist() */ inline std::list doublelist( const char* str ) { return str2list_wrap( str ); } std::list charlist( const char* str ) { std::list Lstr; std::list Lchar; str2list(Lstr,str); std::list< std::string >::const_iterator it; for ( it= Lstr.begin(); it!=Lstr.end(); ++it ) { if ( (*it)[0] == '\'' ) { if ( it->size() == 1 ) { Lchar.push_back( ' ' ); // blank ++it; } else { Lchar.push_back( (*it)[1] ); } } else { Lchar.push_back( (*it)[0] ); } } return Lchar; } ///< Sinónimo de \c makeList_char(). /** Retorna la lista de caracteres \c (char) construida en base a \c "str". Usa \c str2list() pero se brinca las comillas simples \c ('). - No necesita que cada letra venga entre comillas simples. - Si alguno de los valores tiene más de un caracter, usa el primero e ignora los demás. \dontinclude test_str2list.cpp \skipline test::charlist() \until }} \see test_str2list::test_makeList_char() */ inline std::list makeList_char( const char* str ) { return charlist( str ); } /** Almacena en \c "M<<>>" la matriz de hileras construida en base a \c "str". - Cada renglón de la matriz debe estar entre caracteres \c '|'. - Para obtener cada renglón se usa \c str2list(). - La matriz se retorna como una lista de listas de hileras. - Ignora sublistas nulas pues \c "M<<>>" nunca contiene sublistas nulas. - Siempre modifica el valor de \c "M<<>>". - Retorna la longitud de la sublista más grande de \c "M<<>>" (para calcular cuántas columnas tiene la matriz). \dontinclude test_str2list.cpp \skipline test::str2matrix() \until }} \see test_str2list::test_str2matrix() */ template size_t str2matrix( std::list< std::list >& M , const char* str ) { M.clear(); if ( str == 0) { return 0; } if (*str == 0) { return 0; } size_t mx = 0; // max sublist length M.push_back( std::list() ); while ( *str != 0 ) { typename std::list & L = M.back(); // L: last list in M<<>> str = str2list( L , str ); if ( *str!=0 ) { str++; } mx = ( L.size()() ); } } if ( M.back().empty() ) { M.pop_back(); } return mx; // NOTA: implementado con plantillas para evitar usar el archivo str2list.cpp } /** Almacena en \c MATRIX[][] la matriz construida en base a \c "str". Usa \c str2matrix() junto con \c ATON_wrap::ATON(). \tparam N tipo de dato: { int long double } \tparam ATON_wrap Empaque \c ATON() alrededor del convertidor: { atoi() atol() atof() } \tparam Nrows Cantidad de filas de \c MATRIX[][]. \tparam Ncols Cantidad de columnas de \c MATRIX[][]. */ template void matrix2list_wrap( N MATRIX[Nrows][Ncols] , const char* str ) { std::list< std::list > Mlist; size_t NCOLS = str2matrix( Mlist , str ); // Mlist <== str size_t NROWS = Mlist.size(); NROWS = ( NROWS > :: const_iterator it; typename std::list :: const_iterator jt; it = Mlist.begin(); for ( size_t i=0; ibegin(); for ( size_t j=0; jend() ) { MATRIX[i][j] = 0; } else { MATRIX[i][j] = ATON_wrap::ATON( jt->c_str() ); jt++; } } } } /** Almacena en \c M[][] la matriz de enteros \c (int) construida en base a \c "str". Usa \c str2matrix() junto con \c atoi(). \dontinclude test_str2list.cpp \skipline test::intmatrix() \until }} \see test_str2list::test_intmatrix() */ template inline void intmatrix( int M[Nrows][Ncols] , const char* str ) { return matrix2list_wrap( M , str ); } /** Almacena en \c M[][] la matriz de enteros \c (long) construida en base a \c "str". Usa \c str2matrix() junto con \c atol(). \dontinclude test_str2list.cpp \skipline test::longmatrix() \until }} \see test_str2list::test_longmatrix() */ template inline void longmatrix( long M[Nrows][Ncols] , const char* str ) { return matrix2list_wrap( M , str ); } /** Almacena en \c M[][] la matriz de flotantes construida en base a \c "str". Usa \c str2matrix() junto con \c atof(). \dontinclude test_str2list.cpp \skipline test::doublematrix() \until }} \see test_str2list::test_doublematrix() */ template inline void doublematrix( double M[Nrows][Ncols] , const char* str ) { return matrix2list_wrap( M,str ); } #include // memset() /** Almacena en \c M[][] la matriz de caracteres construida en base a \c "str". Usa \c str2matrix() pero se brinca las comillas simples \c ('). - No necesita que cada letra venga entre comillas simples. - Si alguno de los valores tiene más de un caracter, usa el primero e ignora los demás. \dontinclude test_str2list.cpp \skipline test::charmatrix() \until }} \see test_str2list::test_charmatrix() */ template inline void charmatrix( char M[Nrows][Ncols] , const char* str ) { std::list< std::list > Mstr; str2matrix( Mstr, str ); memset( M, ' ', sizeof(M) ); // llena la matriz de blancos unsigned i,j; // paralelos (i<->it) && (j<->jt) std::list< std::list >::const_iterator it; std::list::const_iterator jt; for ( i=0,it=Mstr.begin(); (i& Mrenglon = (*it); for ( j=0,jt=Mrenglon.begin(); (jsize() == 1 ) { M[i][j] = ' '; // blank ++jt; } else { M[i][j] = (*jt)[1]; } } else { M[i][j] = (*jt)[0]; } } } return; } #endif // str2list_h // EOF: str2list.h