347 lines
9.5 KiB
C++
347 lines
9.5 KiB
C++
#ifndef __GOSTRINGS_HPP__
|
|
#define __GOSTRINGS_HPP__
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace gostrings {
|
|
|
|
inline int Compare(const std::string &a, const std::string &b) {
|
|
if (a == b) return 0;
|
|
return (a < b) ? -1 : 1;
|
|
}
|
|
|
|
inline bool Contains(const std::string &s, const std::string &substr) {
|
|
return s.find(substr) != std::string::npos;
|
|
}
|
|
|
|
inline bool ContainsAny(const std::string &s, const std::string &chars) {
|
|
return s.find_first_of(chars) != std::string::npos;
|
|
}
|
|
|
|
inline bool ContainsFunc(const std::string &s, bool (*f)(char)) {
|
|
for (char c : s) {
|
|
if (f(c)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
inline int Count(const std::string &s, const std::string &substr) {
|
|
if (substr.empty()) {
|
|
return static_cast<int>(s.size()) + 1;
|
|
}
|
|
int count = 0;
|
|
size_t pos = 0;
|
|
while ((pos = s.find(substr, pos)) != std::string::npos) {
|
|
++count;
|
|
pos += substr.length();
|
|
}
|
|
return count;
|
|
}
|
|
|
|
struct CutPrefixResult {
|
|
std::string after;
|
|
bool found;
|
|
};
|
|
|
|
struct CutSuffixResult {
|
|
std::string before;
|
|
bool found;
|
|
};
|
|
|
|
struct CutResult {
|
|
CutPrefixResult prefix;
|
|
CutSuffixResult suffix;
|
|
inline bool found() const {
|
|
return prefix.found && suffix.found;
|
|
}
|
|
};
|
|
|
|
inline CutResult Cut(const std::string &s, const std::string &sep) {
|
|
size_t pos = s.find(sep);
|
|
if (pos == std::string::npos) {
|
|
return {{"", false}, {"", false}};
|
|
}
|
|
return { {s.substr(pos + sep.length()), true}, {s.substr(0, pos), true} };
|
|
}
|
|
|
|
inline CutPrefixResult CutPrefix(const std::string &s, const std::string &prefix) {
|
|
if (s.substr(0, prefix.length()) == prefix) {
|
|
return {s.substr(prefix.length()), true};
|
|
}
|
|
return {"", false};
|
|
}
|
|
|
|
inline CutSuffixResult CutSuffix(const std::string &s, const std::string &suffix) {
|
|
if (s.length() >= suffix.length() &&
|
|
s.substr(s.length() - suffix.length()) == suffix) {
|
|
return {s.substr(0, s.length() - suffix.length()), true};
|
|
}
|
|
return {"", false};
|
|
}
|
|
|
|
inline std::vector<std::string> Fields(const std::string &s) {
|
|
std::vector<std::string> result;
|
|
size_t start = s.find_first_not_of(" \t\n\r\f\v");
|
|
while (start != std::string::npos) {
|
|
size_t end = s.find_first_of(" \t\n\r\f\v", start);
|
|
result.push_back(s.substr(start, end - start));
|
|
start = s.find_first_not_of(" \t\n\r\f\v", end);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::vector<std::string> FieldsFunc(const std::string &s, bool (*f)(char)) {
|
|
std::vector<std::string> result;
|
|
size_t start = 0;
|
|
while (start < s.length()) {
|
|
while (start < s.length() && f(s[start])) {
|
|
++start;
|
|
}
|
|
if (start >= s.length()) break;
|
|
size_t end = start;
|
|
while (end < s.length() && !f(s[end])) {
|
|
++end;
|
|
}
|
|
result.push_back(s.substr(start, end - start));
|
|
start = end;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline bool HasPrefix(const std::string &s, const std::string &prefix) {
|
|
return s.substr(0, prefix.length()) == prefix;
|
|
}
|
|
|
|
inline bool HasSuffix(const std::string &s, const std::string &suffix) {
|
|
return s.length() >= suffix.length() &&
|
|
s.substr(s.length() - suffix.length()) == suffix;
|
|
}
|
|
|
|
inline size_t Index(const std::string &s, const std::string &substr) {
|
|
size_t pos = s.find(substr);
|
|
return (pos == std::string::npos) ? -1 : pos;
|
|
}
|
|
|
|
inline size_t IndexAny(const std::string &s, const std::string &chars) {
|
|
size_t pos = s.find_first_of(chars);
|
|
return (pos == std::string::npos) ? -1 : pos;
|
|
}
|
|
|
|
inline size_t IndexByte(const std::string &s, char c) {
|
|
size_t pos = s.find(c);
|
|
return (pos == std::string::npos) ? -1 : pos;
|
|
}
|
|
|
|
inline size_t IndexFunc(const std::string &s, bool (*f)(char)) {
|
|
for (size_t i = 0; i < s.length(); ++i) {
|
|
if (f(s[i])) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
inline std::string Join(const std::vector<std::string> &elems, const std::string &sep) {
|
|
std::string result;
|
|
for (size_t i = 0; i < elems.size(); ++i) {
|
|
result += elems[i];
|
|
if (i < elems.size() - 1) {
|
|
result += sep;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline size_t LastIndex(const std::string &s, const std::string &substr) {
|
|
size_t pos = s.rfind(substr);
|
|
return (pos == std::string::npos) ? -1 : pos;
|
|
}
|
|
|
|
inline size_t LastIndexAny(const std::string &s, const std::string &chars) {
|
|
size_t pos = s.find_last_of(chars);
|
|
return (pos == std::string::npos) ? -1 : pos;
|
|
}
|
|
|
|
inline size_t LastIndexByte(const std::string &s, char c) {
|
|
size_t pos = s.rfind(c);
|
|
return (pos == std::string::npos) ? -1 : pos;
|
|
}
|
|
|
|
inline size_t LastIndexFunc(const std::string &s, bool (*f)(char)) {
|
|
for (size_t i = s.length(); i-- > 0;) {
|
|
if (f(s[i])) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
inline std::string Repeat(const std::string &s, int count) {
|
|
if (count <= 0) return "";
|
|
std::string result;
|
|
for (int i = 0; i < count; ++i) {
|
|
result += s;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::string Replace(const std::string &s, const std::string &old, const std::string &newstr, int n) {
|
|
std::string result = s;
|
|
size_t pos = 0;
|
|
int count = 0;
|
|
while ((pos = result.find(old, pos)) != std::string::npos) {
|
|
if (n != -1 && count >= n) break;
|
|
result.replace(pos, old.length(), newstr);
|
|
pos += newstr.length();
|
|
++count;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::string ReplaceAll(const std::string &s, const std::string &old, const std::string &newstr) {
|
|
return Replace(s, old, newstr, -1);
|
|
}
|
|
|
|
inline std::vector<std::string> Split(const std::string &s, const std::string &sep) {
|
|
std::vector<std::string> result;
|
|
size_t start = 0;
|
|
size_t end;
|
|
while ((end = s.find(sep, start)) != std::string::npos) {
|
|
result.push_back(s.substr(start, end - start));
|
|
start = end + sep.length();
|
|
}
|
|
result.push_back(s.substr(start));
|
|
return result;
|
|
}
|
|
|
|
inline std::vector<std::string> SplitAfter(const std::string &s, const std::string &sep) {
|
|
std::vector<std::string> result;
|
|
size_t start = 0;
|
|
size_t end;
|
|
while ((end = s.find(sep, start)) != std::string::npos) {
|
|
result.push_back(s.substr(start, end + sep.length() - start));
|
|
start = end + sep.length();
|
|
}
|
|
result.push_back(s.substr(start));
|
|
return result;
|
|
}
|
|
|
|
inline std::vector<std::string> SplitAfterN(const std::string &s, const std::string &sep, int n) {
|
|
std::vector<std::string> result;
|
|
size_t start = 0;
|
|
size_t end;
|
|
int count = 0;
|
|
while (count < n - 1 && (end = s.find(sep, start)) != std::string::npos) {
|
|
result.push_back(s.substr(start, end + sep.length() - start));
|
|
start = end + sep.length();
|
|
++count;
|
|
}
|
|
result.push_back(s.substr(start));
|
|
return result;
|
|
}
|
|
|
|
inline std::vector<std::string> SplitN(const std::string &s, const std::string &sep, int n) {
|
|
std::vector<std::string> result;
|
|
size_t start = 0;
|
|
size_t end;
|
|
int count = 0;
|
|
while (count < n - 1 && (end = s.find(sep, start)) != std::string::npos) {
|
|
result.push_back(s.substr(start, end - start));
|
|
start = end + sep.length();
|
|
++count;
|
|
}
|
|
result.push_back(s.substr(start));
|
|
return result;
|
|
}
|
|
|
|
inline std::string ToLower(const std::string &s) {
|
|
std::string result = s;
|
|
for (char &c : result) {
|
|
c = static_cast<char>(tolower(static_cast<unsigned char>(c)));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::string ToUpper(const std::string &s) {
|
|
std::string result = s;
|
|
for (char &c : result) {
|
|
c = static_cast<char>(toupper(static_cast<unsigned char>(c)));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::string Trim(const std::string &s, const std::string &cutset) {
|
|
size_t start = s.find_first_not_of(cutset);
|
|
if (start == std::string::npos) return "";
|
|
size_t end = s.find_last_not_of(cutset);
|
|
return s.substr(start, end - start + 1);
|
|
}
|
|
|
|
inline std::string TrimFunc(const std::string &s, bool (*f)(char)) {
|
|
size_t start = 0;
|
|
while (start < s.length() && f(s[start])) {
|
|
++start;
|
|
}
|
|
if (start == s.length()) return "";
|
|
size_t end = s.length() - 1;
|
|
while (end > start && f(s[end])) {
|
|
--end;
|
|
}
|
|
return s.substr(start, end - start + 1);
|
|
}
|
|
|
|
inline std::string TrimLeft(const std::string &s, const std::string &cutset) {
|
|
size_t start = s.find_first_not_of(cutset);
|
|
if (start == std::string::npos) return "";
|
|
return s.substr(start);
|
|
}
|
|
|
|
inline std::string TrimLeftFunc(const std::string &s, bool (*f)(char)) {
|
|
size_t start = 0;
|
|
while (start < s.length() && f(s[start])) {
|
|
++start;
|
|
}
|
|
return s.substr(start);
|
|
}
|
|
|
|
inline std::string TrimPrefix(const std::string &s, const std::string &prefix) {
|
|
if (s.substr(0, prefix.length()) == prefix) {
|
|
return s.substr(prefix.length());
|
|
}
|
|
return s;
|
|
}
|
|
|
|
inline std::string TrimRight(const std::string &s, const std::string &cutset) {
|
|
size_t end = s.find_last_not_of(cutset);
|
|
if (end == std::string::npos) return "";
|
|
return s.substr(0, end + 1);
|
|
}
|
|
|
|
inline std::string TrimRightFunc(const std::string &s, bool (*f)(char)) {
|
|
size_t end = s.length();
|
|
while (end > 0 && f(s[end - 1])) {
|
|
--end;
|
|
}
|
|
return s.substr(0, end);
|
|
}
|
|
|
|
inline std::string TrimSpace(const std::string &s) {
|
|
return Trim(s, " \t\n\r\f\v");
|
|
}
|
|
|
|
inline std::string TrimSuffix(const std::string &s, const std::string &suffix) {
|
|
if (s.length() >= suffix.length() &&
|
|
s.substr(s.length() - suffix.length()) == suffix) {
|
|
return s.substr(0, s.length() - suffix.length());
|
|
}
|
|
return s;
|
|
}
|
|
|
|
} // namespace gostrings
|
|
|
|
|
|
|
|
#endif // __GOSTRINGS_HPP__
|