11 #ifndef ccuty_ccstring
12 #define ccuty_ccstring
47 inline constexpr
unsigned long long strid(
const char* str,
49 unsigned long long id = 0) {
50 return (!*str || last==0) ?
id :
ccuty::strid(str+1, last-1, (
id<<8) + *str);
56 inline unsigned long long strid(
const std::string& str,
int last = 32767) {
74 void reset() {pos_ = 0; size_ = 0;}
83 void pattern(
const std::string& delimiters) {
84 pattern_ = delimiters;
85 if (delimiters.empty()) spaces_ =
true;
98 void pos(
size_t val) {pos_ = val;}
101 size_t pos()
const {
return pos_;}
107 size_t pos_{0}, size_{0};
108 std::string pattern_;
110 bool spaces_{
false}, quotes_{
false}, trim_{
true};
143 inline size_t strsplit(std::vector<std::string>& tokens,
161 inline size_t strsplit(std::string& left, std::string& right,
181 inline size_t regsplit(std::vector<std::string>& tokens,
215 inline std::string
trimmed(
const std::string& str) {
216 std::string result(str);
222 inline std::string
unquoted(
const std::string& str) {
223 std::string result(str);
229 inline int icompare(
const std::string& a,
const std::string& b) {
230 size_t len = a.length() < b.length() ? a.length() : b.length();
231 for (
size_t k=0; k<len; ++k) {
235 return a.length()==b.length() ? 0 : a.length()<b.length() ? -1 : +1;
239 inline bool iequal(
const std::string& str1,
const std::string& str2) {
240 return str1.length()!=str2.length() ?
false :
icompare(str1, str2)==0;
245 for (
auto& c : str) c = char(::
tolower(c));
250 for (
auto& c : str) c = char(::
toupper(c));
254 inline std::string
tolower(
const std::string& str) {
259 inline std::string
toupper(
const std::string& str) {
265 if (str ==
"true") {var =
true;
return true;}
266 else if (str ==
"false") {var =
false;
return true;}
267 else {var =
false;
return false;}
274 var = ::strtol(str.c_str(), &p, 0);
275 if (p ==
nullptr || errno != 0) {var = 0;
return false;}
else return true;
279 inline bool from_string(
unsigned long& var,
const std::string& str) {
282 var = ::strtoul(str.c_str(), &p, 0);
283 if (p ==
nullptr || errno != 0) {var = 0;
return false;}
else return true;
290 var = ::strtof(str.c_str(), &p);
291 if (p ==
nullptr || errno != 0) {var = 0;
return false;}
else return true;
298 var = ::strtod(str.c_str(), &p);
299 if (p ==
nullptr || errno != 0) {var = 0;
return false;}
else return true;
303 inline bool from_string(
long double& var,
const std::string& str) {
306 var = ::strtold(str.c_str(), &p);
307 if (p ==
nullptr || errno != 0) {var = 0;
return false;}
else return true;
311 inline int system(
const std::string& command) {
318 if (str.empty())
return;
319 if (d.size_ == 0) d.size_ = str.size();
320 if (d.pos_ >= d.size_)
return;
322 const char *p = str.c_str() + d.pos_;
323 const char *end = str.c_str() + d.size_;
326 && ((d.spaces_ && ::isspace(*p))
327 || d.pattern_.find(*p) != std::string::npos)
329 if (p >= end) {str.clear();
return;}
333 && ((d.spaces_ && ::isspace(*end))
334 || d.pattern_.find(*end) != std::string::npos)
336 if (end < p) {str.clear();
return;}
339 if (*p ==
'"' || *p ==
'\'') ++p;
340 if (*end ==
'"' || *end ==
'\'') --end;
341 if (end < p) {str.clear();
return;}
343 str.assign(p,
size_t(end-p+1));
349 if (d.size_ == 0) d.size_ = str.size();
350 if (d.pos_ >= d.size_) {d.matched_ = 0;
return false;}
352 const char* p = str.c_str() + d.pos_;
356 while (*p != 0 && ::isspace(*p)) ++p;
357 if (*p == 0) {d.pos_ = d.size_; d.matched_ = 0;
return false;}
359 const char* begtok = p;
361 if (d.quotes_ && (*p ==
'"' || *p ==
'\'')) {
363 while (*p != 0 && *p != quote) ++p;
365 token.assign(begtok+1,
size_t(p-begtok));
366 d.pos_ = d.size_; d.matched_ = 0;
return true;
369 token.assign(begtok+1,
size_t(p-begtok-1));
371 delim = ::isspace(*p) ?
' ' : quote;
377 && (!d.spaces_ || !::isspace(*p))
378 && (!d.quotes_ || (*p !=
'"' && *p !=
'\''))
379 && d.pattern_.find(*p) == std::string::npos) ++p;
381 if (d.spaces_ && ::isspace(*p)) {
382 token.assign(begtok,
size_t(p-begtok));
386 else if (d.quotes_ && (*p ==
'"' || *p ==
'\'')) {
387 token.assign(begtok,
size_t(p-begtok));
392 const char* endtok = p-1;
394 while (endtok > begtok && ::isspace(*endtok)) --endtok;
396 token.assign(begtok,
size_t(endtok-begtok+1));
398 d.pos_ = d.size_; d.matched_ = 0;
return true;
401 d.pos_ = size_t(p - str.c_str() + 1);
411 while (*p != 0 && ::isspace(*p)) ++p;
414 d.pos_ = d.size_; d.matched_ = 0;
return true;
417 else if (d.pattern_.find(*p) != std::string::npos) {
418 d.pos_ = size_t(p - str.c_str() + 1);
423 d.pos_ = size_t(p - str.c_str() + (d.trim_ ? 0 : 1));
429 inline size_t strsplit(std::string& left, std::string& right,
const std::string& str,
432 left.clear(); right.clear();
435 delim.pattern_.clear();
442 inline size_t strsplit(std::vector<std::string>& tokens,
const std::string& str,
446 if (limit <= 0) limit = 32767;
447 while (
int(tokens.size()) < limit-1 &&
ccuty::strtoken(tok, str, delim)) tokens.push_back(tok);
448 delim.pattern_.clear();
450 if (
ccuty::strtoken(tok, str, delim) && !tok.empty()) tokens.push_back(tok);
451 return tokens.size();
454 inline size_t regsplit(std::vector<std::string>& tokens,
const std::string& str,
457 if (str.empty())
return 0;
458 std::regex expr(delim.spaces_ ?
"[:space:]"+delim.pattern_ : delim.pattern_);
459 const char *p = str.c_str(), *prefix = p;
461 auto trimRight = [&tokens](
const char* beg,
const char* end,
bool atEnd) {
462 while (end >= beg && ::isspace(*end)) --end;
463 if (end < beg) {
if (!atEnd) tokens.push_back(
"");}
464 else tokens.push_back(std::string(beg, end-beg+1));
467 while (limit <= 0 ||
int(tokens.size()) < limit-1) {
469 while (*p != 0 && ::isspace(*p)) ++p;
470 if (*p == 0) {prefix = p;
break;}
474 if (!std::regex_search(p, m, expr))
break;
476 if (!delim.trim_) tokens.push_back(std::string(prefix, p-prefix+m.position()));
477 else (trimRight)(prefix, p+m.position()-1,
false);
478 p += m.position() + m.length();
484 if (!delim.trim_) tokens.push_back(std::string(prefix));
486 while (*prefix != 0 && ::isspace(*prefix)) ++prefix;
487 if (*prefix != 0) (trimRight)(prefix, prefix+::strlen(prefix)-1,
true);
490 return tokens.size();