/** @file
$ Id $
$ Date $
$ Author $
@ copy & copy ; Marc W & auml ; ckerlin
@ license LGPL , see file < a href = " license.html " > COPYING < / a >
$ Log $
Revision 1.7 2005 / 11 / 29 12 : 38 : 46 marc
- make it compilable with gcc 4.0 .2 and newer doxygen
- added split and join
Revision 1.6 2005 / 04 / 07 20 : 48 : 42 marc
docu : new doxygen , new grouping
Revision 1.5 2005 / 01 / 28 07 : 53 : 09 marc
doc : hint regarding iomanip on string
Revision 1.4 2004 / 12 / 20 13 : 24 : 08 marc
from string conversion throws exception in case of failure
Revision 1.3 2004 / 12 / 20 07 : 40 : 36 marc
documentation improved , new grouping
Revision 1.2 2004 / 12 / 16 13 : 09 : 47 marc
inlines forgotten
Revision 1.1 2004 / 10 / 07 09 : 31 : 30 marc
new feature
*/
# ifndef __MRW__STRING__HPP__
# define __MRW__STRING__HPP__
# include <mrw/exception.hpp>
# include <string>
# include <sstream>
# include <list>
namespace mrw {
/** @defgroup StdExt Extensions for C++ Standard Libraries
@ section stdextfeatures Features
@ subsection stdextstringfeatures Extensions to std : : string
- Shift operator to shift any kind of values into a string
without the need for a stingstream .
- Addition operators to add , means concatenate , any kind of
value ( e . g . integer ) to a string without the need for a
stringstream .
- Function mrw : : string to convert any type of variable to a
string without the need for a stringstream .
- Function mrw : : to < > to convert a string to any type of
variable without the need for a stringstream .
@ subsection stdextstlfeatures Extensions to STL containers
- Shift operator to shift elements from and to all STL
containers .
@ subsection stdextstreams Extensions for stream handling
- Function mrw : : getline to read a whole line from a stream ( file )
without the need of a buffer and without having to check
whether the buffer was large enough .
@ section stdextmotivation Motivation
There are some feature I am often missing in standard C + + . They
are relatively easy to obtain , but they could be even simpler . I
am mainly a convinced C + + programmer , because I love
simplicity . This means , to convert an integer to a string ,
something like this is not simple enough :
@ code
int i ;
std : : string s ;
[ . . . ]
std : : stringstream ss ;
ss < < " length is: " < < i < < " mm " ;
ss > > s ;
@ endcode
Why can ' t it simply be :
@ code
int i ;
std : : string s ;
[ . . . ]
s < < " length is: " < < i < < " mm " ;
@ endcode
Or :
@ code
int i ;
std : : string s ;
[ . . . ]
s + = i ; // convert i to string and append it
@ endcode
Because we are using the great and powerful C + + language , it can
be ! That ' s why you need this module .
In addition to the shift in and shift out operator for strings ,
you also get a shhift in and shift out operator for all STL
container classes :
@ code
std : : list < int > l ;
l < < 1 < < 2 < < < 3 < < 4 ;
int i1 , i2 , i3 , i4 ;
l > > i1 > > i2 > > i3 > > i4 ;
@ endcode
And the possibility to add strings to integers and vice versa :
@ code
std : : string s ( " x " ) ;
s = 1 + s + 2 ; // s=="1x2"
@ endcode
@ warning Please note that global namespace is polluted with some
operators . If you don ' t want this , just don ' t include any of
these include files files . There ' s no impact from this module ,
if you don ' t include a header , since all code is inline .
@ note The signature of some string functions has changed :
They may now throw exceptions if conversion fails !
( since 1.4 .1 )
*/
//@{
/** @defgroup stdextstring String extensions
The string extensions give you a lot of new powerful operations :
- convert anything to string :
@ code
std : : string s = mrw : : string ( 15 ) ;
@ endcode
- convert a string to something else :
@ code
double d = mrw : : to < double > ( " 3.1415926535898 " ) ;
@ endcode
- shift values into a string :
@ code
std : : string s ;
s < < " length is: " < < i < < " mm " ;
@ endcode
- read values from a string :
@ code
std : : string s ( " 1 2 4 8 " ) ;
int i1 , i2 , i3 , i4 ;
s > > i1 > > i2 > > i3 > > i4 ;
@ endcode
- add all kind of integer and floating point numbers to a string :
@ code
std : : string s ( " hello " ) ;
s + = 4 ;
s = 13.5 + s + 24.8 ;
@ endcode
@ note Please note that you can use the shift operator on
strings , but the IO manipulators from @ c iomanip don ' t
work , nor @ c std : : endl and thelike .
@ note The signature of some string functions has changed :
They may now throw exceptions if conversion fails !
( since 1.4 .1 )
*/
//@}
/** @addtogroup stdextstring
*/
//@{
/** @brief convert any value to a std::string
@ code
std : : string s = mrw : : string ( 15 ) ;
@ endcode
@ param o a value to be converted to std : : string
@ pre \ # include < mrw / string . hpp >
@ pre T must support operator < < to a stream
*/
template < typename T > std : : string string ( const T & o )
throw ( std : : bad_exception ) {
std : : stringstream ss ;
ss < < o ;
return ss . str ( ) ;
}
/** @brief convert std::string to any value
@ code
int i = mrw : : to < int > ( " 15 " ) ;
@ endcode
@ throw mrw : : invalid_argument if value can not be created from string
@ param s the string where a value of type @ c T is extracted from
@ pre \ # include < mrw / string . hpp >
@ pre T must support operator > > from a stream
@ pre operator > > from T must not throw anything else than std : : exception
@ note The signature has changed :
It may now throw exceptions if conversion fails !
( since 1.4 .1 )
*/
template < typename T > T to ( const std : : string & s ) throw ( std : : exception ) {
T o ;
std : : stringstream ss ( s ) ;
if ( ! ( ss > > o ) ) throw mrw : : invalid_argument ( s ) ;
return o ;
}
/** @brief join a string from pieces
@ code
std : : list < std : : string > l ;
l < < " hello " < < " world " ; // needs mrw/list.hpp
std : : string hello_world ( mrw : : join ( l ) ) ;
// hello_world is now "hello world"
@ endcode
@ param l the list of strings to join
@ param delimiter the delimiter between the joined strings
*/
template < template < class STRING > class LIST >
std : : string join ( const LIST < std : : string > & l ,
const std : : string & delimiter = " " )
throw ( std : : bad_exception ) {
std : : string result ;
for ( typename LIST < std : : string > : : const_iterator it ( l . begin ( ) ) ;
it ! = l . end ( ) ; + + it )
result + = ( result . size ( ) ? delimiter : " " ) + mrw : : string ( * it ) ;
return result ;
}
/** @brief split a string into pieces
@ code
std : : string hello_world ( " hello world " ) ;
std : : list < std : : string > l ( mrw : : split ( hello_world ) ) ;
// l contains now "hello" and "world"
@ endcode
@ param text the text that has to be split into tokens
@ param greedy
- @ c true don ' t generate empty tokens , if a delimiter is followed
by another delimiter , both are removed
- @ c false if several delimiters follow each other in the text ,
eat them all and don ' t produce empty tokens
@ param delimiters a list of delimiters , each char in the string is a
delimiter
*/
inline std : : list < std : : string > split ( const std : : string & text ,
bool greedy = true ,
const std : : string & delimiters = " \n \t " )
throw ( std : : bad_exception ) {
std : : list < std : : string > res ;
for ( std : : string : : size_type pos ( 0 ) ;
pos < text . size ( ) ; + + pos ) {
std : : string : : size_type next ( text . find_first_not_of ( delimiters , pos ) ) ;
if ( next ! = pos & & ! greedy ) {
res . push_back ( " " ) ;
} else {
next = std : : min ( text . find_first_of ( delimiters , pos ) , text . size ( ) ) ;
res . push_back ( text . substr ( pos , next - pos ) ) ;
pos = next ;
}
}
return res ;
}
//@}
}
/** @addtogroup stdextstring
*/
//@{
/** @brief append any value to a string
@ code
std : : string s ;
s < < " length is: " < < i < < " mm " ;
@ endcode
@ param s the string , where o is appended
@ param o the value to append to @ c s
@ pre \ # include < mrw / string . hpp >
@ pre T must support operator < < to a stream
*/
template < typename T > std : : string & operator < < ( std : : string & s , const T & o )
throw ( std : : bad_exception ) {
return s + = mrw : : string ( o ) ;
}
/** @brief extract any value from a string
@ code
std : : string s1 ( " length: 15 mm " ) ;
string s2 , s3 ;
int i ( 0 ) ;
s1 > > s2 > > is3 ;
// now: s1=="" s2=="length:" i==15 s3=="mm"
@ endcode
@ throw mrw : : invalid_argument if value can not be created from string
@ param s the string , from which o is extracted
@ param o the value to extract from s
@ note when something is extracted from a string , it is removed
from the string , that means after every shift the string is
shortened by the shifted element
@ pre \ # include < mrw / string . hpp >
@ pre T must support operator > > from a stream
@ note The signature has changed :
It may now throw exceptions if conversion fails !
( since 1.4 .1 )
*/
template < typename T > std : : string & operator > > ( std : : string & s , T & o )
throw ( std : : exception ) {
std : : stringstream ss ( s ) ;
if ( ! ( ss > > o ) ) throw mrw : : invalid_argument ( s ) ;
return ( s = ss . tellg ( ) > 0 ? s . substr ( ss . tellg ( ) ) : " " ) ;
}
/** @brief add a @c unsigned short value to a string
@ code
std : : string s ;
s + " length is: " + i + " mm " ;
@ endcode
@ param s the string , where @ c o is appended
@ param o the value to append to @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string operator + ( const std : : string & s , unsigned short o )
throw ( std : : bad_exception ) {
return s + mrw : : string ( o ) ;
}
/** @brief append a string to a @c unsigned short value
@ code
std : : string s ;
s + " length is: " + i + " mm " ;
@ endcode
@ param s the string , where @ c o is prepended
@ param o the value to prepend in front of @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string operator + ( unsigned short o , const std : : string & s )
throw ( std : : bad_exception ) {
return mrw : : string ( o ) + s ;
}
/** @brief add an @c unsigned int value to a string
@ code
std : : string s ;
s + " length is: " + i + " mm " ;
@ endcode
@ param s the string , where @ c o is appended
@ param o the value to append to @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string operator + ( const std : : string & s , unsigned int o )
throw ( std : : bad_exception ) {
return s + mrw : : string ( o ) ;
}
/** @brief append a string to an @c unsigned int value
@ code
std : : string s ;
s + " length is: " + i + " mm " ;
@ endcode
@ param s the string , where @ c o is prepended
@ param o the value to prepend in front of @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string operator + ( unsigned int o , const std : : string & s )
throw ( std : : bad_exception ) {
return mrw : : string ( o ) + s ;
}
/** @brief add a @c unsigned long value to a string
@ code
std : : string s ;
s + " length is: " + i + " mm " ;
@ endcode
@ param s the string , where @ c o is appended
@ param o the value to append to @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string operator + ( const std : : string & s , unsigned long o )
throw ( std : : bad_exception ) {
return s + mrw : : string ( o ) ;
}
/** @brief append a string to a @c unsigned long value
@ code
std : : string s ;
s + " length is: " + i + " mm " ;
@ endcode
@ param s the string , where @ c o is prepended
@ param o the value to prepend in front of @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string operator + ( unsigned long o , const std : : string & s )
throw ( std : : bad_exception ) {
return mrw : : string ( o ) + s ;
}
/** @brief add a @c signed short value to a string
@ code
std : : string s ;
s + " length is: " + i + " mm " ;
@ endcode
@ param s the string , where @ c o is appended
@ param o the value to append to @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string operator + ( const std : : string & s , signed short o )
throw ( std : : bad_exception ) {
return s + mrw : : string ( o ) ;
}
/** @brief append a string to a @c signed short value
@ code
std : : string s ;
s + " length is: " + i + " mm " ;
@ endcode
@ param s the string , where @ c o is prepended
@ param o the value to prepend in front of @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string operator + ( signed short o , const std : : string & s )
throw ( std : : bad_exception ) {
return mrw : : string ( o ) + s ;
}
/** @brief add an @c signed int value to a string
@ code
std : : string s ;
s + " length is: " + i + " mm " ;
@ endcode
@ param s the string , where @ c o is appended
@ param o the value to append to @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string operator + ( const std : : string & s , signed int o )
throw ( std : : bad_exception ) {
return s + mrw : : string ( o ) ;
}
/** @brief append a string to an @c signed int value
@ code
std : : string s ;
s + " length is: " + i + " mm " ;
@ endcode
@ param s the string , where @ c o is prepended
@ param o the value to prepend in front of @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string operator + ( signed int o , const std : : string & s )
throw ( std : : bad_exception ) {
return mrw : : string ( o ) + s ;
}
/** @brief add a @c signed long value to a string
@ code
std : : string s ;
s + " length is: " + i + " mm " ;
@ endcode
@ param s the string , where @ c o is appended
@ param o the value to append to @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string operator + ( const std : : string & s , signed long o )
throw ( std : : bad_exception ) {
return s + mrw : : string ( o ) ;
}
/** @brief append a string to a @c signed long value
@ code
std : : string s ;
s + " length is: " + i + " mm " ;
@ endcode
@ param s the string , where @ c o is prepended
@ param o the value to prepend in front of @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string operator + ( signed long o , const std : : string & s )
throw ( std : : bad_exception ) {
return mrw : : string ( o ) + s ;
}
/** @brief add a @c unsigned short value to a string
@ code
std : : string s ;
s + = o ;
@ endcode
@ param s the string , where @ c o is appended
@ param o the value to append to @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string & operator + = ( std : : string & s , unsigned short o )
throw ( std : : bad_exception ) {
return s + = mrw : : string ( o ) ;
}
/** @brief add an @c unsigned int value to a string
@ code
std : : string s ;
s + = o ;
@ endcode
@ param s the string , where @ c o is appended
@ param o the value to append to @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string & operator + = ( std : : string & s , unsigned int o )
throw ( std : : bad_exception ) {
return s + = mrw : : string ( o ) ;
}
/** @brief add a @c unsigned long value to a string
@ code
std : : string s ;
s + = o ;
@ endcode
@ param s the string , where @ c o is appended
@ param o the value to append to @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string & operator + = ( std : : string & s , unsigned long o )
throw ( std : : bad_exception ) {
return s + = mrw : : string ( o ) ;
}
/** @brief add a @c signed short value to a string
@ code
std : : string s ;
s + = o ;
@ endcode
@ param s the string , where @ c o is appended
@ param o the value to append to @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string & operator + = ( std : : string & s , signed short o )
throw ( std : : bad_exception ) {
return s + = mrw : : string ( o ) ;
}
/** @brief add an @c signed int value to a string
@ code
std : : string s ;
s + = o ;
@ endcode
@ param s the string , where @ c o is appended
@ param o the value to append to @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string & operator + = ( std : : string & s , signed int o )
throw ( std : : bad_exception ) {
return s + = mrw : : string ( o ) ;
}
/** @brief add a @c signed long value to a string
@ code
std : : string s ;
s + = o ;
@ endcode
@ param s the string , where @ c o is appended
@ param o the value to append to @ c s
@ pre \ # include < mrw / string . hpp >
*/
inline std : : string & operator + = ( std : : string & s , signed long o )
throw ( std : : bad_exception ) {
return s + = mrw : : string ( o ) ;
}
//@}
# endif