00001
00002 #ifndef WIBBLE_STRING_H
00003 #define WIBBLE_STRING_H
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <wibble/operators.h>
00026 #include <wibble/sfinae.h>
00027
00028 #include <string>
00029 #include <set>
00030 #include <vector>
00031 #include <sstream>
00032 #include <cctype>
00033
00034 namespace wibble {
00035 namespace str {
00036
00037 using namespace wibble::operators;
00038
00039
00040
00041 template< typename X >
00042 inline typename TPair< std::ostream, typename X::Type >::First &operator<<(
00043 std::ostream &o, X list )
00044 {
00045 if ( list.empty() )
00046 return o << "[]";
00047
00048 o << "[ ";
00049 while( !list.empty() ) {
00050 o << fmt( list.head() );
00051 if ( !list.tail().empty() )
00052 o << ", ";
00053 list = list.tail();
00054 }
00055 return o << " ]";
00056 }
00057
00058 std::string fmt( const char* f, ... ) __attribute__ ((deprecated));
00059 std::string fmtf( const char* f, ... );
00060
00062 template< typename T >
00063 inline std::string fmt(const T& val)
00064 {
00065 std::stringstream str;
00066 str << val;
00067 return str.str();
00068 }
00069
00070 template<> inline std::string fmt<std::string>(const std::string& val) {
00071 return val;
00072 }
00073 template<> inline std::string fmt<char*>(char * const & val) { return val; }
00074
00075 template< typename C >
00076 inline std::string fmt_container( const C &c, char f, char l )
00077 {
00078 std::string s;
00079 s += f;
00080 if ( c.empty() )
00081 return s + l;
00082
00083 s += ' ';
00084 for ( typename C::const_iterator i = c.begin(); i != c.end(); ++i ) {
00085 s += fmt( *i );
00086 if ( i != c.end() && i + 1 != c.end() )
00087 s += ", ";
00088 }
00089 s += ' ';
00090 s += l;
00091 return s;
00092 }
00093
00094
00095 template< typename X >
00096 inline std::string fmt(const std::set< X >& val) {
00097 return fmt_container( val, '{', '}' );
00098 }
00099
00100
00101 template< typename X >
00102 inline std::string fmt(const std::vector< X > &val) {
00103 return fmt_container( val, '[', ']' );
00104 }
00105
00107 inline std::string basename(const std::string& pathname)
00108 {
00109 size_t pos = pathname.rfind("/");
00110 if (pos == std::string::npos)
00111 return pathname;
00112 else
00113 return pathname.substr(pos+1);
00114 }
00115
00117 inline std::string dirname(const std::string& pathname)
00118 {
00119 size_t pos = pathname.rfind("/");
00120 if (pos == std::string::npos)
00121 return std::string();
00122 else if (pos == 0)
00123
00124 return std::string("/");
00125 else
00126 return pathname.substr(0, pos);
00127 }
00128
00134 std::string normpath(const std::string& pathname);
00135
00137 inline bool startsWith(const std::string& str, const std::string& part)
00138 {
00139 if (str.size() < part.size())
00140 return false;
00141 return str.substr(0, part.size()) == part;
00142 }
00143
00145 inline bool endsWith(const std::string& str, const std::string& part)
00146 {
00147 if (str.size() < part.size())
00148 return false;
00149 return str.substr(str.size() - part.size()) == part;
00150 }
00151
00152 #if ! __GNUC__ || __GNUC__ >= 4
00153
00157 template<typename FUN>
00158 inline std::string trim(const std::string& str, const FUN& classifier)
00159 {
00160 if (str.empty())
00161 return str;
00162
00163 size_t beg = 0;
00164 size_t end = str.size() - 1;
00165 while (beg < end && classifier(str[beg]))
00166 ++beg;
00167 while (end >= beg && classifier(str[end]))
00168 --end;
00169
00170 return str.substr(beg, end-beg+1);
00171 }
00172
00176 inline std::string trim(const std::string& str)
00177 {
00178 return trim(str, ::isspace);
00179 }
00180 #else
00182 inline std::string trim(const std::string& str)
00183 {
00184 if (str.empty())
00185 return str;
00186
00187 size_t beg = 0;
00188 size_t end = str.size() - 1;
00189 while (beg < end && ::isspace(str[beg]))
00190 ++beg;
00191 while (end >= beg && ::isspace(str[end]))
00192 --end;
00193
00194 return str.substr(beg, end-beg+1);
00195 }
00196 #endif
00197
00199 inline std::string toupper(const std::string& str)
00200 {
00201 std::string res;
00202 res.reserve(str.size());
00203 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
00204 res += ::toupper(*i);
00205 return res;
00206 }
00207
00209 inline std::string tolower(const std::string& str)
00210 {
00211 std::string res;
00212 res.reserve(str.size());
00213 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
00214 res += ::tolower(*i);
00215 return res;
00216 }
00217
00219 inline std::string ucfirst(const std::string& str)
00220 {
00221 if (str.empty()) return str;
00222 std::string res;
00223 res += ::toupper(str[0]);
00224 return res + tolower(str.substr(1));
00225 }
00226
00228 inline std::string joinpath(const std::string& path1, const std::string& path2)
00229 {
00230 if (path1.empty())
00231 return path2;
00232 if (path2.empty())
00233 return path1;
00234
00235 if (path1[path1.size() - 1] == '/')
00236 if (path2[0] == '/')
00237 return path1 + path2.substr(1);
00238 else
00239 return path1 + path2;
00240 else
00241 if (path2[0] == '/')
00242 return path1 + path2;
00243 else
00244 return path1 + '/' + path2;
00245 }
00246
00248 std::string urlencode(const std::string& str);
00249
00251 std::string urldecode(const std::string& str);
00252
00254 std::string encodeBase64(const std::string& str);
00255
00257 std::string decodeBase64(const std::string& str);
00258
00271 class Split
00272 {
00273 std::string sep;
00274 std::string str;
00275
00276 public:
00277
00278 class const_iterator
00279 {
00280 const std::string& sep;
00281 const std::string& str;
00282 std::string cur;
00283 size_t pos;
00284
00285 public:
00286 const_iterator(const std::string& sep, const std::string& str) : sep(sep), str(str), pos(0)
00287 {
00288 ++*this;
00289 }
00290 const_iterator(const std::string& sep, const std::string& str, bool) : sep(sep), str(str), pos(std::string::npos) {}
00291
00292 const_iterator& operator++()
00293 {
00294 if (pos == str.size())
00295 pos = std::string::npos;
00296 else
00297 {
00298 size_t end;
00299 if (sep.empty())
00300 if (pos + 1 == str.size())
00301 end = std::string::npos;
00302 else
00303 end = pos + 1;
00304 else
00305 end = str.find(sep, pos);
00306 if (end == std::string::npos)
00307 {
00308 cur = str.substr(pos);
00309 pos = str.size();
00310 }
00311 else
00312 {
00313 cur = str.substr(pos, end-pos);
00314 pos = end + sep.size();
00315 }
00316 }
00317 return *this;
00318 }
00319
00320 std::string remainder() const
00321 {
00322 if (pos == std::string::npos)
00323 return std::string();
00324 else
00325 return str.substr(pos);
00326 }
00327
00328 const std::string& operator*() const
00329 {
00330 return cur;
00331 }
00332 const std::string* operator->() const
00333 {
00334 return &cur;
00335 }
00336 bool operator==(const const_iterator& ti) const
00337 {
00338
00339
00340 return pos == ti.pos;
00341 }
00342 bool operator!=(const const_iterator& ti) const
00343 {
00344
00345
00346 return pos != ti.pos;
00347 }
00348 };
00349
00353 Split(const std::string& sep, const std::string& str) : sep(sep), str(str) {}
00354
00358 const_iterator begin() const { return const_iterator(sep, str); }
00359 const_iterator end() const { return const_iterator(sep, str, false); }
00360 };
00361
00362 template<typename ITER>
00363 std::string join(const ITER& begin, const ITER& end, const std::string& sep = ", ")
00364 {
00365 std::stringstream res;
00366 bool first = true;
00367 for (ITER i = begin; i != end; ++i)
00368 {
00369 if (first)
00370 first = false;
00371 else
00372 res << sep;
00373 res << *i;
00374 }
00375 return res.str();
00376 }
00377
00392 class YamlStream
00393 {
00394 public:
00395
00396 class const_iterator
00397 {
00398 std::istream* in;
00399 std::pair<std::string, std::string> value;
00400 std::string line;
00401
00402 public:
00403 const_iterator(std::istream& in);
00404 const_iterator() : in(0) {}
00405
00406 const_iterator& operator++();
00407
00408 const std::pair<std::string, std::string>& operator*() const
00409 {
00410 return value;
00411 }
00412 const std::pair<std::string, std::string>* operator->() const
00413 {
00414 return &value;
00415 }
00416 bool operator==(const const_iterator& ti) const
00417 {
00418 return in == ti.in;
00419 }
00420 bool operator!=(const const_iterator& ti) const
00421 {
00422 return in != ti.in;
00423 }
00424 };
00425
00426 const_iterator begin(std::istream& in) { return const_iterator(in); }
00427 const_iterator end() { return const_iterator(); }
00428 };
00429
00430 }
00431 }
00432
00433
00434 #endif