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 <cstdarg>
00029 #include <string>
00030 #include <set>
00031 #include <vector>
00032 #include <sstream>
00033 #include <cctype>
00034
00035 namespace wibble {
00036 namespace str {
00037
00038 using namespace wibble::operators;
00039
00040
00041
00042 template< typename X >
00043 inline typename TPair< std::ostream, typename X::Type >::First &operator<<(
00044 std::ostream &o, X list )
00045 {
00046 if ( list.empty() )
00047 return o << "[]";
00048
00049 o << "[ ";
00050 while( !list.empty() ) {
00051 o << fmt( list.head() );
00052 if ( !list.tail().empty() )
00053 o << ", ";
00054 list = list.tail();
00055 }
00056 return o << " ]";
00057 }
00058
00059 static inline std::string fmt( std::string f, ... ) {
00060 char *c;
00061 va_list ap;
00062 va_start( ap, f );
00063 vasprintf( &c, f.c_str(), ap );
00064 std::string ret( c );
00065 free( c );
00066 return ret;
00067 }
00068
00070 template< typename T >
00071 inline std::string fmt(const T& val)
00072 {
00073 std::stringstream str;
00074 str << val;
00075 return str.str();
00076 }
00077
00078 template<> inline std::string fmt<std::string>(const std::string& val) {
00079 return val;
00080 }
00081 template<> inline std::string fmt<char*>(char * const & val) { return val; }
00082
00083 template< typename C >
00084 inline std::string fmt_container( const C &c, char f, char l )
00085 {
00086 std::string s;
00087 s += f;
00088 if ( c.empty() )
00089 return s + l;
00090
00091 s += ' ';
00092 for ( typename C::const_iterator i = c.begin(); i != c.end(); ++i ) {
00093 s += fmt( *i );
00094 if ( i != c.end() && i + 1 != c.end() )
00095 s += ", ";
00096 }
00097 s += ' ';
00098 s += l;
00099 return s;
00100 }
00101
00102
00103 template< typename X >
00104 inline std::string fmt(const std::set< X >& val) {
00105 return fmt_container( val, '{', '}' );
00106 }
00107
00108
00109 template< typename X >
00110 inline std::string fmt(const std::vector< X > &val) {
00111 return fmt_container( val, '[', ']' );
00112 }
00113
00115 inline std::string basename(const std::string& pathname)
00116 {
00117 size_t pos = pathname.rfind("/");
00118 if (pos == std::string::npos)
00119 return pathname;
00120 else
00121 return pathname.substr(pos+1);
00122 }
00123
00125 inline std::string dirname(const std::string& pathname)
00126 {
00127 size_t pos = pathname.rfind("/");
00128 if (pos == std::string::npos)
00129 return std::string();
00130 else if (pos == 0)
00131
00132 return std::string("/");
00133 else
00134 return pathname.substr(0, pos);
00135 }
00136
00142 std::string normpath(const std::string& pathname);
00143
00145 inline bool startsWith(const std::string& str, const std::string& part)
00146 {
00147 if (str.size() < part.size())
00148 return false;
00149 return str.substr(0, part.size()) == part;
00150 }
00151
00153 inline bool endsWith(const std::string& str, const std::string& part)
00154 {
00155 if (str.size() < part.size())
00156 return false;
00157 return str.substr(str.size() - part.size()) == part;
00158 }
00159
00160 #if ! __GNUC__ || __GNUC__ >= 4
00161
00165 template<typename FUN>
00166 inline std::string trim(const std::string& str, const FUN& classifier)
00167 {
00168 if (str.empty())
00169 return str;
00170
00171 size_t beg = 0;
00172 size_t end = str.size() - 1;
00173 while (beg < end && classifier(str[beg]))
00174 ++beg;
00175 while (end >= beg && classifier(str[end]))
00176 --end;
00177
00178 return str.substr(beg, end-beg+1);
00179 }
00180
00184 inline std::string trim(const std::string& str)
00185 {
00186 return trim(str, ::isspace);
00187 }
00188 #else
00190 inline std::string trim(const std::string& str)
00191 {
00192 if (str.empty())
00193 return str;
00194
00195 size_t beg = 0;
00196 size_t end = str.size() - 1;
00197 while (beg < end && ::isspace(str[beg]))
00198 ++beg;
00199 while (end >= beg && ::isspace(str[end]))
00200 --end;
00201
00202 return str.substr(beg, end-beg+1);
00203 }
00204 #endif
00205
00207 inline std::string toupper(const std::string& str)
00208 {
00209 std::string res;
00210 res.reserve(str.size());
00211 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
00212 res += ::toupper(*i);
00213 return res;
00214 }
00215
00217 inline std::string tolower(const std::string& str)
00218 {
00219 std::string res;
00220 res.reserve(str.size());
00221 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
00222 res += ::tolower(*i);
00223 return res;
00224 }
00225
00227 inline std::string ucfirst(const std::string& str)
00228 {
00229 if (str.empty()) return str;
00230 std::string res;
00231 res += ::toupper(str[0]);
00232 return res + tolower(str.substr(1));
00233 }
00234
00236 inline std::string joinpath(const std::string& path1, const std::string& path2)
00237 {
00238 if (path1.empty())
00239 return path2;
00240 if (path2.empty())
00241 return path1;
00242
00243 if (path1[path1.size() - 1] == '/')
00244 if (path2[0] == '/')
00245 return path1 + path2.substr(1);
00246 else
00247 return path1 + path2;
00248 else
00249 if (path2[0] == '/')
00250 return path1 + path2;
00251 else
00252 return path1 + '/' + path2;
00253 }
00254
00256 std::string urlencode(const std::string& str);
00257
00259 std::string urldecode(const std::string& str);
00260
00262 std::string encodeBase64(const std::string& str);
00263
00265 std::string decodeBase64(const std::string& str);
00266
00279 class Split
00280 {
00281 std::string sep;
00282 std::string str;
00283
00284 public:
00285
00286 class const_iterator
00287 {
00288 const std::string& sep;
00289 const std::string& str;
00290 std::string cur;
00291 size_t pos;
00292
00293 public:
00294 const_iterator(const std::string& sep, const std::string& str) : sep(sep), str(str), pos(0)
00295 {
00296 ++*this;
00297 }
00298 const_iterator(const std::string& sep, const std::string& str, bool) : sep(sep), str(str), pos(std::string::npos) {}
00299
00300 const_iterator& operator++()
00301 {
00302 if (pos == str.size())
00303 pos = std::string::npos;
00304 else
00305 {
00306 size_t end;
00307 if (sep.empty())
00308 if (pos + 1 == str.size())
00309 end = std::string::npos;
00310 else
00311 end = pos + 1;
00312 else
00313 end = str.find(sep, pos);
00314 if (end == std::string::npos)
00315 {
00316 cur = str.substr(pos);
00317 pos = str.size();
00318 }
00319 else
00320 {
00321 cur = str.substr(pos, end-pos);
00322 pos = end + sep.size();
00323 }
00324 }
00325 return *this;
00326 }
00327
00328 std::string remainder() const
00329 {
00330 if (pos == std::string::npos)
00331 return std::string();
00332 else
00333 return str.substr(pos);
00334 }
00335
00336 const std::string& operator*() const
00337 {
00338 return cur;
00339 }
00340 const std::string* operator->() const
00341 {
00342 return &cur;
00343 }
00344 bool operator==(const const_iterator& ti) const
00345 {
00346
00347
00348 return pos == ti.pos;
00349 }
00350 bool operator!=(const const_iterator& ti) const
00351 {
00352
00353
00354 return pos != ti.pos;
00355 }
00356 };
00357
00361 Split(const std::string& sep, const std::string& str) : sep(sep), str(str) {}
00362
00366 const_iterator begin() const { return const_iterator(sep, str); }
00367 const_iterator end() const { return const_iterator(sep, str, false); }
00368 };
00369
00370 template<typename ITER>
00371 std::string join(const ITER& begin, const ITER& end, const std::string& sep = ", ")
00372 {
00373 std::stringstream res;
00374 bool first = true;
00375 for (ITER i = begin; i != end; ++i)
00376 {
00377 if (first)
00378 first = false;
00379 else
00380 res << sep;
00381 res << *i;
00382 }
00383 return res.str();
00384 }
00385
00400 class YamlStream
00401 {
00402 public:
00403
00404 class const_iterator
00405 {
00406 std::istream* in;
00407 std::pair<std::string, std::string> value;
00408 std::string line;
00409
00410 public:
00411 const_iterator(std::istream& in);
00412 const_iterator() : in(0) {}
00413
00414 const_iterator& operator++();
00415
00416 const std::pair<std::string, std::string>& operator*() const
00417 {
00418 return value;
00419 }
00420 const std::pair<std::string, std::string>* operator->() const
00421 {
00422 return &value;
00423 }
00424 bool operator==(const const_iterator& ti) const
00425 {
00426 return in == ti.in;
00427 }
00428 bool operator!=(const const_iterator& ti) const
00429 {
00430 return in != ti.in;
00431 }
00432 };
00433
00434 const_iterator begin(std::istream& in) { return const_iterator(in); }
00435 const_iterator end() { return const_iterator(); }
00436 };
00437
00438 }
00439 }
00440
00441
00442 #endif