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 <sstream>
00031 #include <cctype>
00032
00033 namespace wibble {
00034 namespace str {
00035
00036 using namespace wibble::operators;
00037
00038
00039
00040 template< typename X >
00041 inline typename TPair< std::ostream, typename X::Type >::First &operator<<(
00042 std::ostream &o, X list )
00043 {
00044 if ( list.empty() )
00045 return o << "[]";
00046
00047 o << "[ ";
00048 while( !list.empty() ) {
00049 o << fmt( list.head() );
00050 if ( !list.tail().empty() )
00051 o << ", ";
00052 list = list.tail();
00053 }
00054 return o << " ]";
00055 }
00056
00058 template< typename T >
00059 inline std::string fmt(const T& val)
00060 {
00061 std::stringstream str;
00062 str << val;
00063 return str.str();
00064 }
00065
00066 template<> inline std::string fmt<std::string>(const std::string& val) {
00067 return val;
00068 }
00069 template<> inline std::string fmt<char*>(char * const & val) { return val; }
00070
00071
00072 template< typename X >
00073 inline std::string fmt(const std::set< X >& val) {
00074 if ( val.empty() )
00075 return "{}";
00076
00077 std::string s;
00078 for ( typename std::set< X >::iterator i = val.begin();
00079 i != val.end(); ++i ) {
00080 s += fmt( *i );
00081 if ( i != val.end() && i + 1 != val.end() )
00082 s += ", ";
00083 }
00084 return "{ " + s + " }";
00085 }
00086
00088 inline std::string basename(const std::string& pathname)
00089 {
00090 size_t pos = pathname.rfind("/");
00091 if (pos == std::string::npos)
00092 return pathname;
00093 else
00094 return pathname.substr(pos+1);
00095 }
00096
00098 inline std::string dirname(const std::string& pathname)
00099 {
00100 size_t pos = pathname.rfind("/");
00101 if (pos == std::string::npos)
00102 return std::string();
00103 else if (pos == 0)
00104
00105 return std::string("/");
00106 else
00107 return pathname.substr(0, pos);
00108 }
00109
00115 std::string normpath(const std::string& pathname);
00116
00118 inline bool startsWith(const std::string& str, const std::string& part)
00119 {
00120 if (str.size() < part.size())
00121 return false;
00122 return str.substr(0, part.size()) == part;
00123 }
00124
00126 inline bool endsWith(const std::string& str, const std::string& part)
00127 {
00128 if (str.size() < part.size())
00129 return false;
00130 return str.substr(str.size() - part.size()) == part;
00131 }
00132
00133 #if ! __GNUC__ || __GNUC__ >= 4
00134
00138 template<typename FUN>
00139 inline std::string trim(const std::string& str, const FUN& classifier)
00140 {
00141 if (str.empty())
00142 return str;
00143
00144 size_t beg = 0;
00145 size_t end = str.size() - 1;
00146 while (beg < end && classifier(str[beg]))
00147 ++beg;
00148 while (end >= beg && classifier(str[end]))
00149 --end;
00150
00151 return str.substr(beg, end-beg+1);
00152 }
00153
00157 inline std::string trim(const std::string& str)
00158 {
00159 return trim(str, ::isspace);
00160 }
00161 #else
00163 inline std::string trim(const std::string& str)
00164 {
00165 if (str.empty())
00166 return str;
00167
00168 size_t beg = 0;
00169 size_t end = str.size() - 1;
00170 while (beg < end && ::isspace(str[beg]))
00171 ++beg;
00172 while (end >= beg && ::isspace(str[end]))
00173 --end;
00174
00175 return str.substr(beg, end-beg+1);
00176 }
00177 #endif
00178
00180 inline std::string toupper(const std::string& str)
00181 {
00182 std::string res;
00183 res.reserve(str.size());
00184 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
00185 res += ::toupper(*i);
00186 return res;
00187 }
00188
00190 inline std::string tolower(const std::string& str)
00191 {
00192 std::string res;
00193 res.reserve(str.size());
00194 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
00195 res += ::tolower(*i);
00196 return res;
00197 }
00198
00200 inline std::string ucfirst(const std::string& str)
00201 {
00202 if (str.empty()) return str;
00203 std::string res;
00204 res += ::toupper(str[0]);
00205 return res + tolower(str.substr(1));
00206 }
00207
00209 inline std::string joinpath(const std::string& path1, const std::string& path2)
00210 {
00211 if (path1.empty())
00212 return path2;
00213 if (path2.empty())
00214 return path1;
00215
00216 if (path1[path1.size() - 1] == '/')
00217 if (path2[0] == '/')
00218 return path1 + path2.substr(1);
00219 else
00220 return path1 + path2;
00221 else
00222 if (path2[0] == '/')
00223 return path1 + path2;
00224 else
00225 return path1 + '/' + path2;
00226 }
00227
00229 std::string urlencode(const std::string& str);
00230
00232 std::string urldecode(const std::string& str);
00233
00235 std::string encodeBase64(const std::string& str);
00236
00238 std::string decodeBase64(const std::string& str);
00239
00252 class Split
00253 {
00254 std::string sep;
00255 std::string str;
00256
00257 public:
00258
00259 class const_iterator
00260 {
00261 const std::string& sep;
00262 const std::string& str;
00263 std::string cur;
00264 size_t pos;
00265
00266 public:
00267 const_iterator(const std::string& sep, const std::string& str) : sep(sep), str(str), pos(0)
00268 {
00269 ++*this;
00270 }
00271 const_iterator(const std::string& sep, const std::string& str, bool) : sep(sep), str(str), pos(std::string::npos) {}
00272
00273 const_iterator& operator++()
00274 {
00275 if (pos == str.size())
00276 pos = std::string::npos;
00277 else
00278 {
00279 size_t end;
00280 if (sep.empty())
00281 if (pos + 1 == str.size())
00282 end = std::string::npos;
00283 else
00284 end = pos + 1;
00285 else
00286 end = str.find(sep, pos);
00287 if (end == std::string::npos)
00288 {
00289 cur = str.substr(pos);
00290 pos = str.size();
00291 }
00292 else
00293 {
00294 cur = str.substr(pos, end-pos);
00295 pos = end + sep.size();
00296 }
00297 }
00298 return *this;
00299 }
00300
00301 std::string remainder() const
00302 {
00303 if (pos == std::string::npos)
00304 return std::string();
00305 else
00306 return str.substr(pos);
00307 }
00308
00309 const std::string& operator*() const
00310 {
00311 return cur;
00312 }
00313 const std::string* operator->() const
00314 {
00315 return &cur;
00316 }
00317 bool operator==(const const_iterator& ti) const
00318 {
00319
00320
00321 return pos == ti.pos;
00322 }
00323 bool operator!=(const const_iterator& ti) const
00324 {
00325
00326
00327 return pos != ti.pos;
00328 }
00329 };
00330
00334 Split(const std::string& sep, const std::string& str) : sep(sep), str(str) {}
00335
00339 const_iterator begin() const { return const_iterator(sep, str); }
00340 const_iterator end() const { return const_iterator(sep, str, false); }
00341 };
00342
00343 template<typename ITER>
00344 std::string join(const ITER& begin, const ITER& end, const std::string& sep = ", ")
00345 {
00346 std::stringstream res;
00347 bool first = true;
00348 for (ITER i = begin; i != end; ++i)
00349 {
00350 if (first)
00351 first = false;
00352 else
00353 res << sep;
00354 res << *i;
00355 }
00356 return res.str();
00357 }
00358
00373 class YamlStream
00374 {
00375 public:
00376
00377 class const_iterator
00378 {
00379 std::istream* in;
00380 std::pair<std::string, std::string> value;
00381 std::string line;
00382
00383 public:
00384 const_iterator(std::istream& in);
00385 const_iterator() : in(0) {}
00386
00387 const_iterator& operator++();
00388
00389 const std::pair<std::string, std::string>& operator*() const
00390 {
00391 return value;
00392 }
00393 const std::pair<std::string, std::string>* operator->() const
00394 {
00395 return &value;
00396 }
00397 bool operator==(const const_iterator& ti) const
00398 {
00399 return in == ti.in;
00400 }
00401 bool operator!=(const const_iterator& ti) const
00402 {
00403 return in != ti.in;
00404 }
00405 };
00406
00407 const_iterator begin(std::istream& in) { return const_iterator(in); }
00408 const_iterator end() { return const_iterator(); }
00409 };
00410
00411
00412 }
00413 }
00414
00415
00416 #endif